Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
475 views
in Technique[技术] by (71.8m points)

ios - Unexpected behavior when casting an NSNumber to Float

After upgrading to Xcode 9.3 (9E145) my App showed some unexpected behavior. It seems that the issue is with a cast of an NSNumber to a Float. I use the as type cast operator for this. See the following example.

let n = NSNumber.init(value: 1.12)
let m = NSNumber.init(value: 1.00)

let x = n as? Float
let y = m as? Float

let xd = n as? Double

let z = Float(truncating: n)

Here, the first cast fails, i.e. x == nil. The second cast succeeds and the instantiation of a Float with the init:truncating constructor also succeeds, i.e. z == 1.12. The cast of n to a Double succeeds, which, to me, makes no sense at all.

Can anyone explain this behavior to me? I.e. can anyone give me a good reason why the cast of n to a Float fails? Is this a bug? If this is intended behavior, can you please reference the location in the Swift documentation that describes this?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

This is a consequence of SE-0170 NSNumber bridging and Numeric types, implemented in Swift 4:

as? for NSNumber should mean "Can I safely express the value stored in this opaque box called a NSNumber as the value I want?".

1.12 is a floating point literal, and inferred as a Double, so NSNumber(value: 1.12) is “boxing” the 64-bit floating point value closest to 1.12. Converting that to a 32-bit Float does not preserve this value:

let n = NSNumber(value: 1.12)
let x = Float(truncating: n) // Or: let x = n.floatValue
let nn = NSNumber(value: x)
print(n == nn) // false

On the other hand, 1.0 can be represented exactly as a Float:

let m = NSNumber(value: 1.0)
let y = m.floatValue
let mm = NSNumber(value: y)
print(m == mm) // true

and that is why casting m as? Float succeeds. Both

n.floatValue
Float(truncating: n)

can be used to ”truncate” the number to the closest representable 32-bit floating point value.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...