问题描述
这是Xcode 7.3.1 playground中的一个简单代码:
var str =8.7
print (double(str))
输出令人惊讶:
可选(8.6999999999999993)
也可以, Float(str) : 8.69999981
这家伙的任何想法或理由?
此外,我应该如何将8.7转换为8.7作为Double(或Float)? swift中的编辑
:
(str as NSString).doubleValue returns 8.7
现在,确定。但我的问题,仍然,没有得到一个完整的答案。我们找到了一个替代,但为什么我们不能依赖Double(8.7)。
()。
6.9as NSString).doubleValue // prints 6.9000000000000004所以,问题再次打开。
这里有两个不同的问题。首先 - 如
中提到的注释 - 二进制浮点数不能精确地表示
数字 8.7 。 Swift使用IEEE 754标准表示
单精度和双精度浮点数,如果您指定
let x = 8.7
那么最近的可表示数存储在 code>,即
8.699999999999999289457264239899814128875732421875
有关这方面的更多信息可以在优秀的
Q& A
第二个问题是:为什么这个数字有时打印为8.7
,有时打印为8.6999999999999993?
let str = 8.7
print(Double(str))//可选(8.6999999999999993)
let x = 8.7
print(x)// 8.7
是 Double(8.7)与不同8.7 ?是否比
更精确?
要回答这些问题,我们需要知道 print()
function works:
- 如果参数符合 CustomStringConvertible ,打印函数调用其 description 属性并将结果
打印到标准输出。 - 否则,如果参数符合 CustomDebugStringConvertible ,
打印函数调用是 debugDescription 属性并打印
- 否则,使用一些其他机制。 (此处不会导入我们的
目的。)
Double 类型符合 CustomStringConvertible ,因此
let x = 8.7
print(x)// 8.7
产生与
相同的输出let x = 8.7
print(x.description)// 8.7
但在
中会发生什么?let str =8.7
print(Double(str))//可选(8.6999999999999993)
(str)是可选和 struct可选不会
符合 CustomStringConvertible ,而是
CustomDebugStringConvertible 。因此,打印函数调用
可选的 debugDescription 属性,其中
调用底层 Double 的 debugDescription 。
因此,除了是可选的之外,数字输出是
,与
let x = 8.7
print(x.debugDescription)// 8.6999999999999993
描述和 debugDescription
的浮点值?从Swift源代码可以看到
,它们最终调用:
- digits10 - 可以无更改地表示的小数位数,
- max_digits10 - 区分此类型所有值所需的小数位数。
所以 description 创建一个具有较少十进制数字的字符串。那个
字符串可以转换为 Double ,并返回一个给出
的字符串,结果相同。
debugDescription 创建一个具有更多小数位数的字符串,因此
任何两个不同的浮点值将产生不同的输出。
摘要:
- 大多数十进制数不能精确表示为二元
浮点值。 - 描述和 debugDescription 浮点
点类型的方法使用不同的精度转换为
字符串。因此,与打印非可选值相比, - 打印可选浮点值使用的转换精度不同。
因此,在您的情况下,您可能希望在打印之前打开可选的
:
let str =8.7
if let d = Double(str){
print(d)// 8.7
}
为了更好的控制,请使用 NSNumberFormatter 与%。< precision> f 格式。
Here is a simple code in Xcode 7.3.1 playground:
var str = "8.7"print(Double(str))
the output is suprising:Optional(8.6999999999999993)
also, Float(str) gives: 8.69999981
Any thoughts or reasons on this guys?Any references to this would be appreciated.
Also, how should I then convert "8.7" to 8.7 as Double (or Float)?
Edit
in swift:
(str as NSString).doubleValue returns 8.7
Now, that is Ok. But my question, still, does not get a complete answer. We have found an alternative but why can we not rely on Double("8.7"). Please, give a deeper insight on this.
Edit 2
("6.9" as NSString).doubleValue // prints 6.9000000000000004
So, the question opens up again.
There are two different issues here. First – as already mentioned inthe comments – a binary floating point number cannot represent thenumber 8.7 precisely. Swift uses the IEEE 754 standard for representingsingle- and double-precision floating point numbers, and if you assign
let x = 8.7
then the closest representable number is stored in x, and that is
8.699999999999999289457264239899814128875732421875
Much more information about this can be found in the excellentQ&A Is floating point math broken?.
The second issue is: Why is the number sometimes printed as "8.7"and sometimes as "8.6999999999999993"?
let str = "8.7" print(Double(str)) // Optional(8.6999999999999993) let x = 8.7 print(x) // 8.7
Is Double("8.7") different from 8.7? Is one more precise thanthe other?
To answer these questions, we need to know how the print()function works:
- If an argument conforms to CustomStringConvertible, the print function calls its description property and prints the resultto the standard output.
- Otherwise, if an argument conforms to CustomDebugStringConvertible,the print function calls is debugDescription property and printsthe result to the standard output.
- Otherwise, some other mechanism is used. (Not imported here for ourpurpose.)
The Double type conforms to CustomStringConvertible, therefore
let x = 8.7 print(x) // 8.7
produces the same output as
let x = 8.7 print(x.description) // 8.7
But what happens in
let str = "8.7" print(Double(str)) // Optional(8.6999999999999993)
Double(str) is an optional, and struct Optional does notconform to CustomStringConvertible, but toCustomDebugStringConvertible. Therefore the print function callsthe debugDescription property of Optional, which in turncalls the debugDescription of the underlying Double.Therefore – apart from being an optional – the number output isthe same as in
let x = 8.7 print(x.debugDescription) // 8.6999999999999993
But what is the difference between description and debugDescriptionfor floating point values? From the Swift source code one can seethat both ultimately call the swift_floatingPointToStringfunction in Stubs.cpp, with the Debug parameter set to false and true, respectively.This controls the precision of the number to string conversion:
int Precision = std::numeric_limits<T>::digits10; if (Debug) { Precision = std::numeric_limits<T>::max_digits10; }
For the meaning of those constants, see http://en.cppreference.com/w/cpp/types/numeric_limits:
- digits10 – number of decimal digits that can be represented without change,
- max_digits10 – number of decimal digits necessary to differentiate all values of this type.
So description creates a string with less decimal digits. Thatstring can be converted to a Double and back to a string givingthe same result.debugDescription creates a string with more decimal digits, so thatany two different floating point values will produce a different output.
Summary:
- Most decimal numbers cannot be represented exactly as a binaryfloating point value.
- The description and debugDescription methods of the floatingpoint types use a different precision for the conversion to astring. As a consequence,
- printing an optional floating point value uses a different precision for the conversion than printing a non-optional value.
Therefore in your case, you probably want to unwrap the optionalbefore printing it:
let str = "8.7" if let d = Double(str) { print(d) // 8.7 }
For better control, use NSNumberFormatter or formattedprinting with the %.<precision>f format.
这篇关于swift:在将字符串转换为double时发生错误的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!