首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >关于浮点数的mult和div运算的差异

关于浮点数的mult和div运算的差异
EN

Stack Overflow用户
提问于 2014-01-17 14:13:53
回答 4查看 202关注 0票数 0

这两种情况的计算精度是否有差异:

1) x = y / 1000d;

2) x = y * 0.001d;

编辑:不应该添加C#标签。问题只是从“浮点”的角度提出的。我不想知道什么是更快的,我需要知道什么样的情况会给我‘更好的精确度’。

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2014-01-18 12:04:55

不,它们不一样--至少在我的处理器上使用我的机器上的版本(只有标准的C# 4.5.1) --有足够的微妙之处,我不想宣称它会在所有机器上或所有语言上都这样做。毕竟,这可能是一个特定于语言的问题。

使用我的DoubleConverter类来显示double的确切值,经过几次尝试和错误之后,下面是一个C#程序,它至少在我的机器上显示了一个不同之处:

代码语言:javascript
运行
复制
using System;

class Program
{
    static void Main(string[] args)
    {
        double input = 9;
        double x1 = input / 1000d;
        double x2 = input * 0.001d;

        Console.WriteLine(x1 == x2);
        Console.WriteLine(DoubleConverter.ToExactString(x1));
        Console.WriteLine(DoubleConverter.ToExactString(x2));
    }
}

输出:

代码语言:javascript
运行
复制
False
0.00899999999999999931998839741709161899052560329437255859375
0.009000000000000001054711873393898713402450084686279296875

我可以用Microsoft编译器在C中再现这一点--如果它是可怕的C风格,请原谅,但我认为它至少说明了其中的不同之处:

代码语言:javascript
运行
复制
#include <stdio.h>

void main(int argc, char **argv) {
    double input = 9;
    double x1 = input / 1000;
    double x2 = input * 0.001;
    printf("%s\r\n", x1 == x2 ? "Same" : "Not same");
    printf("%.18f\r\n", x1);
    printf("%.18f\r\n", x2);
}

输出:

代码语言:javascript
运行
复制
Not same
0.008999999999999999
0.009000000000000001

我还没有研究过具体的细节,但这对我来说是有意义的,因为除以1,000并乘以“最接近的double到0.001”并不是相同的逻辑操作.因为0.001不能准确地表示为double。离0.001最近的double实际上是:

代码语言:javascript
运行
复制
0.001000000000000000020816681711721685132943093776702880859375

..。所以这就是你最后被乘的原因。你早早就失去了信息,希望它能与你失去的信息相对应,除以1000。在某些情况下,情况似乎并非如此。

票数 2
EN

Stack Overflow用户

发布于 2014-01-26 22:14:37

你是在基数10编程,但浮点数是2,你可以在基数2中表示1,000,但在基2中不能表示0.001,所以你选择了错误的数字来问你的问题,在计算机x/1000 != x*0.001上,你可能会在大多数情况下得到幸运的四舍五入和更高的精度,但这不是一个数学标识。

也许这就是你的问题,也许你想知道为什么x/1000 != x*0.001。这个问题的答案是,因为这是一台二进制计算机,它使用的是基2而不是基10,当到基2的时候,有0.001的转换问题,你不能用IEEE浮点数精确地表示这个分数。

在基数10中,我们知道,如果分母中有一个因子为3的分数(在分子中没有一个来抵消它),我们最终会有一个无限重复的模式,基本上我们不能用有限的数字集合来精确地表示这个数字。

1/3 =0.33333。

同样的问题,当你试图在基数2.10= 2*5中表示1/10时,2是好的1/2,但5是真正的问题1/5。

1/10 (1/1000工作方式相同)。初等长除法:

代码语言:javascript
运行
复制
       0 000110011
     ----------
1010 | 1.000000
         1010
       ------
          1100 
          1010
          ----
            10000
             1010
             ----
              1100
              1010
              ----
                10

我们必须继续拉零,直到我们得到10000,10到16,一次,剩下的6,放下下一个零。10进入12,1次余数2。我们重复这个模式,所以你最终得到了这个001100110011,永远重复。浮点是一个固定的位数,所以我们不能表示无限模式。

如果你的问题和除以4一样,等于乘以1/4。这是一个不同的问题。答案是,它应该是相同的,消耗更多的循环和/或逻辑做一个除法,而不是乘,但最终计算出相同的答案。

票数 1
EN

Stack Overflow用户

发布于 2014-01-17 14:22:39

可能不会。无论如何,编译器(或JIT)可能会将第一种情况转换为第二种情况,因为乘法通常比除法更快。您必须通过编译代码(无论是否启用优化)来检查这一点,然后使用诸如IL反汇编程序或.NET反射器之类的工具检查生成的IL,并/或在运行时使用调试器检查本机代码。

票数 -2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/21187911

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档