迅速:将字符串转换为双精度的问题

发布于 2021-01-31 23:56:59

这是Xcode 7.3.1 Playground中的简单代码:

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

输出令人惊讶: Optional(8.6999999999999993)

另外,Float(str)给出:8.69999981

对这个家伙有什么想法或理由吗?任何对此的引用将不胜感激。

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

编辑

迅速地:

(str作为NSString).doubleValue返回8.7

现在,可以。但是,我的问题仍然没有得到完整的答案。我们找到了一个替代方法,但是为什么我们不能依赖Double(“ 8.7”)。请对此提供更深入的了解。

编辑2

(“ 6.9” as NSString).doubleValue //打印6.9000000000000004

因此,问题再次出现。

关注者
0
被浏览
126
1 个回答
  • 面试哥
    面试哥 2021-01-31
    为面试而生,有面试问题,就找面试哥。

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

    let x = 8.7
    

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

    8.699999999999999289457264239899814128875732421875
    

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

    let str = "8.7"
    print(Double(str)) // Optional(8.6999999999999993)
    
    let x = 8.7
    print(x) // 8.7
    

    Double("8.7")从不同8.7?一个比另一个更精确吗?

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

    • 如果参数符合CustomStringConvertible,则打印函数将调用其description属性并将结果打印到标准输出。
    • 否则,如果参数符合CustomDebugStringConvertible,则打印函数调用is 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)) // Optional(8.6999999999999993)
    

    Double(str)可选的 ,并struct Optional不会 符合CustomStringConvertible,而是要CustomDebugStringConvertible。因此,print函数调用的debugDescription属性Optional,该属性又调用debugDescription基础的Double。因此,除了是可选的以外,数字输出与

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

    但是descriptiondebugDescription
    浮点值之间有什么区别?从Swift的源代码中,可以看到两者最终都swift_floatingPointToString
    Stubs.cpp中调用了Debug参数分别设置为false和的函数true。这控制了数字到字符串转换的精度:

      int Precision = std::numeric_limits<T>::digits10;
      if (Debug) {
        Precision = std::numeric_limits<T>::max_digits10;
      }
    

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

    • digits10 –可以不改变地表示的小数位数,
    • max_digits10 –区分此类型的所有值所必需的小数位数。

    因此,description创建一个具有较少十进制数字的字符串。该字符串可以转换为a Double并返回给相同结果的字符串。
    debugDescription创建具有更多十进制数字的字符串,以便任何两个不同的浮点值将产生不同的输出。


    摘要:

    • 大多数十进制数字不能完全表示为二进制浮点值。
    • 浮点类型的descriptiondebugDescription方法使用不同的精度来转换为字符串。作为结果,
    • 打印 可选 浮点值与打印非可选值所使用的精度不同。

    因此,根据您的情况,您可能希望在打印可选件之前将其拆开:

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

    为了更好地控制,请使用NSNumberFormatter%.<precision>f格式或对格式进行格式化。

    另一种选择是使用(NS)DecimalNumber而不是Double



推荐阅读
知识点
面圈网VIP题库

面圈网VIP题库全新上线,海量真题题库资源。 90大类考试,超10万份考试真题开放下载啦

去下载看看