简体   繁体   中英

Why does CGFloat casted from Float not exhibit CGFloat behavior?

I have this simple example where I try to draw a circle. This code below does not give me a circle.

import UIKit

class PlayingCardView: UIView {

    override func draw(_ rect: CGRect) {
        if let context = UIGraphicsGetCurrentContext(){

            context.addArc(center: CGPoint(x: bounds.midX, 
                           y: bounds.midY), radius: 100.0, 
                           startAngle: 0, 
                           endAngle: CGFloat(2.0*Float.pi), 
                           clockwise: true)

            context.setLineWidth(5.0)
            UIColor.red.setStroke()
            context.strokePath()
            print(2.0*CGFloat.pi)
            print(CGFloat(2.0*Float.pi))
        } 
    }
}

This is what I get with the above code:

with output:

6.283185307179586 6.283185005187988

from the print statements which correspond to 2.0*CGFloat.pi and CGFloat(2.0*Float.pi) respectively.

Updating the code to this (I only change the endAngle in context.addArc to be 2.0*CGFloat.pi instead of CGFloat(2.0*Float.pi)

import UIKit

class PlayingCardView: UIView {

    override func draw(_ rect: CGRect) {
        if let context = UIGraphicsGetCurrentContext(){

            context.addArc(center: CGPoint(x: bounds.midX, 
                           y: bounds.midY), radius: 100.0, 
                           startAngle: 0, 
                           endAngle: 2.0*CGFloat.pi, 
                           clockwise: true)

            context.setLineWidth(5.0)
            UIColor.red.setStroke()
            context.strokePath()
            print(2.0*CGFloat.pi)
            print(CGFloat(2.0*Float.pi))
        } 
    }
}

I get this drawing (The circle is there)

There is obviously a difference between the casted CGFloat from Float and CGFloat. Does anybody know what it is and why this behavior is useful in Swift?

On a 64-bit platform, CGFloat is (essentially) Double , a 64-bit floating point number, whereas Float is a 32-bit floating point number.

So 2.0*Float.pi is “2π with 32-bit precision”, and converting that to the 64-bit quantity CGFloat preserves the value, without increasing the precision.

That is why 2.0*CGFloat.pi != CGFloat(2.0*Float.pi) . The former is “2π with 64-bit precision”, and is what you should pass to the drawing functions.

In your particular case, CGFloat(2.0*Float.pi) is a tiny bit smaller than 2.0*CGFloat.pi , so that only an invisibly short arc is drawn (from radians 0.0 to approximately -0.00000003).

For a full circle you can alternatively use

let radius: CGFloat = 100.0
context.addEllipse(in: CGRect(x: bounds.midX - radius, y: bounds.midY - radius,
                              width: 2.0 * radius, height: 2.0 * radius))

and avoid all rounding problems.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM