为什么这个表达式会导致浮点错误?

2024-05-04

所以浮点运算是inexact http://en.wikipedia.org/wiki/Floating_point但这并不能完全解释这里发生的事情:

[46] pry(main)> a=0.05
=> 0.05
[47] pry(main)> a=a*26.0/65
=> 0.02

所以我们得到了我们所期望的,我们得到了正确的答案,世界继续美丽地转动。但我们后来重写了这个函数,当我们这样做时,我们交换了行a=a*26.0/65 for a*=26.0/65是不是很好,我们少打了一个字!让我们看看这对我们来说效果如何?

[48] pry(main)> a=0.05
=> 0.05
[49] pry(main)> a*=26.0/65
=> 0.020000000000000004
[50] pry(main)> 26.0/65
=> 0.4

这表明a*=b与写作不一样a=a*b。这似乎不是正常的浮点舍入错误,因为这些数字都不应该舍入为浮点(尾数对于 26.0、26.0/65、65.0 中的每一个都应该足够长)

我确信幕后发生了一些微妙的事情,我想知道到底发生了什么?


浮点格式的有效数有足够的位来表示 26/65 是不正确的。 (“有效数”是首选术语。有效数是线性的。尾数是对数的。)

The significand of a binary floating-point number is a binary integer. This integer is scaled according to the exponent. To represent 26/65, which is .4, in binary floating-point, we must represent it as an integer multiplied by a power of two. For example, an approximation to .4 is 1•2-1 = .5. A better approximation is 3•2-3=.375. Better still is 26•2-4 = .40625.

However, no matter what integer you use for the significand or what exponent you use, this format can never be exactly .4. Suppose you had .4 = f•2e, where f and e are integers. Then 2/5 = f•2e, so 2/(5f) = 2e, and then 1/(5f) = 2e-1 and 5f = 21-e. For that to be true, 5 would have to be a power of two. It is not, so you cannot have .4 = f•2e.

In IEEE-754 64-bit binary floating-point, the significand has 53 bits. With this, the closest representable value to .4 is 0.40000000000000002220446049250313080847263336181640625, which equals 3602879701896397•2-53.

现在让我们看看您的计算。在a=0.05, 0.05转换为浮点数,生成 0.05000000000000000277555756156289135105907917022705078125。

In a*26.0/65, a*26.0首先被评估。精确的数学结果将四舍五入到最接近的可表示值,生成 1.3000000000000000444089209850062616169452667236328125。然后除以 65。同样,结果被四舍五入,得到 0.0200000000000000004163336342344337026588618755340576171875。当 Ruby 打印这个值时,它显然认为它足够接近 0.02,因此它只能显示“.02”而不是完整的值。这是合理的,因为如果将打印值 0.02 转换回浮点数,您将再次获得实际值 0.0200000000000000004163336342344337026588618755340576171875。因此,“.02”在某种意义上可以很好地代表 0.0200000000000000004163336342344337026588618755340576171875。

在你的替代表达中,你有a*=26.0/65。在这之中,26.0/65首先被评估。这会产生 0.40000000000000002220446049250313080847263336181640625。这与第一个表达式不同因为您以不同的顺序执行了运算,所以舍入了不同的数字。可能会发生第一个表达式中的值被向下舍入的情况,而这个不同的值由于它恰好相对于以浮点表示的值而发生的位置而被向上舍入。

然后将该值乘以a。这会产生 0.02000000000000000388578058618804789148271083831787109375。请注意,该值比第一个表达式的结果更远离 0.02。您的 Ruby 实现知道这一点,因此它确定打印“.02”不足以准确表示它。相反,它显示更多数字,显示 0.020000000000000004。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

为什么这个表达式会导致浮点错误? 的相关文章

  • 获取块参数个数

    我需要获取给定块所采用的参数数量 例如 foobar 1 2 3 a b c def foobar x y z block need to obtain number of arguments in block which would be
  • 红宝石边缘情况

    ruby 有一些边缘情况很难解释 因为解析会带来一些有趣的问题 我在这里列出其中两个 如果您知道更多 请添加到列表中 def foo 5 end this one works if tmp foo puts tmp to s end How
  • 转储 YAML 时如何强制使用双引号?

    我有一个小脚本来自动化 YAML 文件中的一些操作 我读取原始 YAML 文件并将其转换为哈希 然后dump http ruby doc org stdlib 1 8 6 libdoc yaml rdoc YAML html method
  • 如何在 Rails 控制器中调用通道方法?

    我有一个订阅用户的 ActionCable 方法 如果启动新的 convo 我也希望用户订阅新频道 我无法找出在控制器中调用通道方法的正确语法 更新 问题是消息在发送时附加到聊天框 但是当发送第一条消息时 Websocket 连接尚未建立
  • 从 Ruby 中的 DateTime 变量获取时间

    我在 ruby 中工作 我有一个包含数据库中今天的日期时间的对象 我只想要时间截断数据 我怎样才能得到那个 Try 日期时间 strftime http www ruby doc org stdlib 1 9 3 libdoc date r
  • 通过推送通知唤醒

    Suppose 有一些对象 例如 一个数组a 和依赖于对象的条件 例如 a empty 当前线程以外的某些线程可以操作该对象 a 因此条件评估值的真实性会随着时间的推移而变化 如何让当前线程在代码中的某个时刻休眠 并在条件满足时通过推送通知
  • 如何向 Time.now 添加两周?

    如何在 Ruby 中向当前 Time now 添加两周 我有一个使用 DataMapper 的小型 Sinatra 项目 在保存之前 我有一个字段填充了当前时间加上两周 但未按需要工作 任何帮助是极大的赞赏 我收到以下错误 NoMethod
  • 如何计算带有偏移量的异或?

    我想用不同的偏移量进行异或计算以在计算中列出 例子 key 0 1 0 text 0 1 0 1 0 1 0 1 1 1 异或计算 key 0 text 0 key 1 text 1 key 2 text 2 key 0 text 3 ke
  • 如何从 ruby​​ 中的字符串中删除所有非数字?

    用户输入数字的形式如下 1 800 432 4567 800 432 4567 800 432 4566 800 432 4567 1 800 432 4567 800 432 4567 我希望所有这些都变成没有特殊字符的剥离版本 例如18
  • REXML - 如何提取单个元素

    我正在用 ruby 编写一些验收测试 其中涉及断言响应 XML 中值的存在 我的 XML 是这样的
  • Rails:named_scope、lambda 和块

    我认为以下两个是等效的 named scope admin lambda company id conditions gt company id company id named scope admin lambda do company
  • Nokogiri 保持 HTML 实体不变

    我希望 Nokogiri 保持 HTML 实体不变 但它似乎正在将实体转换为实际的符号 例如 Nokogiri HTML fragment p reg p to s 结果是 p p 似乎没有什么可以将原始 HTML 返回给我 inner h
  • 在 ruby​​ 中下载多个 FTP 文件,如 d*.txt

    我需要连接到 ftp 站点并下载一堆名为 D txt 的文件 最多 6 个 你能帮我用 Ruby 编写这个代码吗 下面的代码只是 ftp Net FTP new ftp server site ftp login user pwd ftp
  • 如何进行带有偏差的浮点舍入(始终向上或向下舍入)?

    我想以偏置舍入浮动 要么总是向下 要么总是向上 代码中有一个特定的点 我需要这个 程序的其余部分应该像往常一样四舍五入到最接近的值 例如 我想四舍五入到最接近的 1 10 倍数 最接近 7 10 的浮点数约为 0 69999998807 但
  • 红宝石接球和效率

    catch在 Ruby 中意味着跳出深度嵌套的代码 在 Java 中 例如用Java也可以达到同样的效果try catch用于处理异常 但它被认为是糟糕的解决方案 而且效率非常低 在 Ruby 中 我们有处理异常的方法begin raise
  • RoR - Rails 中的大文件上传

    我有一个 Rails Web 应用程序 允许用户上传视频 视频存储在 NFS 安装的目录中 当前的设置适用于较小的文件 但我也需要支持大文件上传 最多 4GB 当我尝试上传 4GB 文件时 它最终会发生 但从用户体验的角度来看很糟糕 上传开
  • 如何从 Ruby 中的特定相对路径加载文件?

    我正在制作一颗供内部使用的宝石 在其中 我从另一个目录加载一些 YAML in
  • 使用rSpec 测试delayed_job 链的最佳方法是什么?

    目前 当我的代码中有一个延迟方法时 如下所示 CommentMailer delay deliver comments comment true 我在规范中写了这样的内容 dj mock DelayProxy CommentMailer s
  • 使用浮点/双除法比较可约分数

    假设我有两个分数 a b 和 c d 其中 a b c d 都是大于 0 的整数 使用以下函数检查它们的相等性是否安全 bool are equal fractions int a int b int c int d return stat
  • 在 Sinatra 中运行后台进程

    我有 Sinatra Rails 应用程序和一个启动一些漫长过程的操作 通常我会为后台作业排队 但这种情况太简单了 后台进程很少启动 所以队列是一个开销 那么如何在没有队列的情况下运行后台进程呢 get build logs project

随机推荐