swift:将字符串转换为双行的问题

时间:2022-09-10 22:39:59

Here is a simple code in Xcode 7.3.1 playground:

以下是Xcode 7.3.1中的一个简单代码:

var str = "8.7" print(Double(str))

var str = "8.7"打印(双(str)

the output is suprising: Optional(8.6999999999999993)

输出是出乎意料的:可选(8.69999999999999999999999993)

also, Float(str) gives: 8.69999981

同时,浮动(str)为: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)?

另外,我应该如何将“8.7”转换为8.7作为Double(或Float)?

Edit

编辑

in swift:

迅速:

(str as NSString).doubleValue returns 8.7

作为NSString(str)。doubleValue返回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.

现在,这是好的。但是我的问题仍然没有得到一个完整的答案。我们已经找到了另一种选择,但为什么我们不能依赖双精度(“8.7”)呢?请给出一个更深刻的见解。

Edit 2

编辑2

("6.9" as NSString).doubleValue // prints 6.9000000000000004

(“6.9”NSString)。6.9000000000000004 doubleValue / /打印

So, the question opens up again.

这个问题又出现了。

3 个解决方案

#1


9  

There are two different issues here. First – as already mentioned in the comments – a binary floating point number cannot represent the number 8.7 precisely. Swift uses the IEEE 754 standard for representing single- and double-precision floating point numbers, and if you assign

这里有两个不同的问题。首先,正如注释中已经提到的,二进制浮点数不能精确地表示8.7。Swift使用IEEE 754标准来表示单精度和双精度浮点数,如果您分配的话

let x = 8.7

then the closest representable number is stored in x, and that is

然后,最接近的可表示数存储在x中,即。

8.699999999999999289457264239899814128875732421875

Much more information about this can be found in the excellent Q&A Is floating point math broken?.

更多关于这方面的信息可以在优秀的问答中找到:浮点数学被破坏了吗?


The second issue is: Why is the number sometimes printed as "8.7" and sometimes as "8.6999999999999993"?

第二个问题是:为什么数字有时印成“8.7”,有时印成“8.6999999999999999999993”?

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 than the other?

Double(“8.7”)与8.7不同吗?一个比另一个更精确吗?

To answer these questions, we need to know how the print() function works:

要回答这些问题,我们需要知道print()函数是如何工作的:

  • If an argument conforms to CustomStringConvertible, the print function calls its description property and prints the result to the standard output.
  • 如果参数符合CustomStringConvertible,打印函数调用其description属性并将结果打印到标准输出。
  • Otherwise, if an argument conforms to CustomDebugStringConvertible, the print function calls is debugDescription property and prints the result to the standard output.
  • 否则,如果参数符合CustomDebugStringConvertible,打印函数调用是debugDescription属性,并将结果打印到标准输出。
  • Otherwise, some other mechanism is used. (Not imported here for our purpose.)
  • 否则,将使用其他一些机制。(不是为我们的目的进口的。)

The Double type conforms to CustomStringConvertible, therefore

因此,双类型符合CustomStringConvertible

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 not conform to CustomStringConvertible, but to CustomDebugStringConvertible. Therefore the print function calls the debugDescription property of Optional, which in turn calls the debugDescription of the underlying Double. Therefore – apart from being an optional – the number output is the same as in

Double(str)是可选的,而struct optional不符合CustomStringConvertible,而是CustomDebugStringConvertible。因此,print函数调用Optional的debugDescription属性,后者反过来调用底层Double的debugDescription。因此,除了是可选的之外,输出的数字与in相同

let x = 8.7
print(x.debugDescription) // 8.6999999999999993

But what is the difference between description and debugDescription for floating point values? From the Swift source code one can see that both ultimately call the swift_floatingPointToString function in Stubs.cpp, with the Debug parameter set to false and true, respectively. This controls the precision of the number to string conversion:

但是浮点值的description和debugDescription有什么区别呢?从Swift源代码可以看到,两者最终都在存根中调用swift_floatingPointToString函数。cpp,调试参数分别设置为false和true。它控制数字到字符串转换的精度:

  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:

关于这些常量的含义,请参见http://en.cppreference.com/w/cpp/types/numeric_limits:

  • digits10 – number of decimal digits that can be represented without change,
  • digits10 -十进制数的数目,可以不加改变地表示,
  • max_digits10 – number of decimal digits necessary to differentiate all values of this type.
  • max_digits10 -区分此类型的所有值所需的十进制数。

So description creates a string with less decimal digits. That string can be converted to a Double and back to a string giving the same result. debugDescription creates a string with more decimal digits, so that any two different floating point values will produce a different output.

因此,描述创建了一个小数位数较少的字符串。可以将该字符串转换为双字符串,然后返回一个字符串,得到相同的结果。debugDescription创建一个具有更多小数位数的字符串,因此任何两个不同的浮点值都将产生不同的输出。


Summary:

简介:

  • Most decimal numbers cannot be represented exactly as a binary floating point value.
  • 大多数十进制数不能精确地表示为二进制浮点值。
  • The description and debugDescription methods of the floating point types use a different precision for the conversion to a string. 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 optional before printing it:

因此,在您的情况下,您可能需要在打印之前打开可选的包装:

let str = "8.7"
if let d = Double(str) {
    print(d) // 8.7
}

For better control, use NSNumberFormatter or formatted printing with the %.<precision>f format.

为了更好地控制,使用NSNumberFormatter或格式化打印%。 <精度> f格式。

Another option can be to use (NS)DecimalNumber instead of Double (e.g. for currency amounts), see e.g. Round Issue in swift.

另一种选择是使用(NS)小数而不是双位数(例如货币数量),参见swift中的Round问题。

#2


1  

I would use:

我将使用:

let doubleValue = NSNumberFormatter().numberFromString(str)?.doubleValue

#3


0  

You can use this code may be useful.

您可以使用这段代码可能会有用。

print(str.doubleValue)

#1


9  

There are two different issues here. First – as already mentioned in the comments – a binary floating point number cannot represent the number 8.7 precisely. Swift uses the IEEE 754 standard for representing single- and double-precision floating point numbers, and if you assign

这里有两个不同的问题。首先,正如注释中已经提到的,二进制浮点数不能精确地表示8.7。Swift使用IEEE 754标准来表示单精度和双精度浮点数,如果您分配的话

let x = 8.7

then the closest representable number is stored in x, and that is

然后,最接近的可表示数存储在x中,即。

8.699999999999999289457264239899814128875732421875

Much more information about this can be found in the excellent Q&A Is floating point math broken?.

更多关于这方面的信息可以在优秀的问答中找到:浮点数学被破坏了吗?


The second issue is: Why is the number sometimes printed as "8.7" and sometimes as "8.6999999999999993"?

第二个问题是:为什么数字有时印成“8.7”,有时印成“8.6999999999999999999993”?

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 than the other?

Double(“8.7”)与8.7不同吗?一个比另一个更精确吗?

To answer these questions, we need to know how the print() function works:

要回答这些问题,我们需要知道print()函数是如何工作的:

  • If an argument conforms to CustomStringConvertible, the print function calls its description property and prints the result to the standard output.
  • 如果参数符合CustomStringConvertible,打印函数调用其description属性并将结果打印到标准输出。
  • Otherwise, if an argument conforms to CustomDebugStringConvertible, the print function calls is debugDescription property and prints the result to the standard output.
  • 否则,如果参数符合CustomDebugStringConvertible,打印函数调用是debugDescription属性,并将结果打印到标准输出。
  • Otherwise, some other mechanism is used. (Not imported here for our purpose.)
  • 否则,将使用其他一些机制。(不是为我们的目的进口的。)

The Double type conforms to CustomStringConvertible, therefore

因此,双类型符合CustomStringConvertible

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 not conform to CustomStringConvertible, but to CustomDebugStringConvertible. Therefore the print function calls the debugDescription property of Optional, which in turn calls the debugDescription of the underlying Double. Therefore – apart from being an optional – the number output is the same as in

Double(str)是可选的,而struct optional不符合CustomStringConvertible,而是CustomDebugStringConvertible。因此,print函数调用Optional的debugDescription属性,后者反过来调用底层Double的debugDescription。因此,除了是可选的之外,输出的数字与in相同

let x = 8.7
print(x.debugDescription) // 8.6999999999999993

But what is the difference between description and debugDescription for floating point values? From the Swift source code one can see that both ultimately call the swift_floatingPointToString function in Stubs.cpp, with the Debug parameter set to false and true, respectively. This controls the precision of the number to string conversion:

但是浮点值的description和debugDescription有什么区别呢?从Swift源代码可以看到,两者最终都在存根中调用swift_floatingPointToString函数。cpp,调试参数分别设置为false和true。它控制数字到字符串转换的精度:

  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:

关于这些常量的含义,请参见http://en.cppreference.com/w/cpp/types/numeric_limits:

  • digits10 – number of decimal digits that can be represented without change,
  • digits10 -十进制数的数目,可以不加改变地表示,
  • max_digits10 – number of decimal digits necessary to differentiate all values of this type.
  • max_digits10 -区分此类型的所有值所需的十进制数。

So description creates a string with less decimal digits. That string can be converted to a Double and back to a string giving the same result. debugDescription creates a string with more decimal digits, so that any two different floating point values will produce a different output.

因此,描述创建了一个小数位数较少的字符串。可以将该字符串转换为双字符串,然后返回一个字符串,得到相同的结果。debugDescription创建一个具有更多小数位数的字符串,因此任何两个不同的浮点值都将产生不同的输出。


Summary:

简介:

  • Most decimal numbers cannot be represented exactly as a binary floating point value.
  • 大多数十进制数不能精确地表示为二进制浮点值。
  • The description and debugDescription methods of the floating point types use a different precision for the conversion to a string. 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 optional before printing it:

因此,在您的情况下,您可能需要在打印之前打开可选的包装:

let str = "8.7"
if let d = Double(str) {
    print(d) // 8.7
}

For better control, use NSNumberFormatter or formatted printing with the %.<precision>f format.

为了更好地控制,使用NSNumberFormatter或格式化打印%。 <精度> f格式。

Another option can be to use (NS)DecimalNumber instead of Double (e.g. for currency amounts), see e.g. Round Issue in swift.

另一种选择是使用(NS)小数而不是双位数(例如货币数量),参见swift中的Round问题。

#2


1  

I would use:

我将使用:

let doubleValue = NSNumberFormatter().numberFromString(str)?.doubleValue

#3


0  

You can use this code may be useful.

您可以使用这段代码可能会有用。

print(str.doubleValue)