【问题标题】:Rounding a Double without using Round or Truncate在不使用 Round 或 Truncate 的情况下舍入 Double
【发布时间】:2012-07-03 16:04:35
【问题描述】:

我被问到以下问题,但我不知道如何回答。我想知道是否有人可以提供帮助:

使用 C#,但不使用任何数学函数(不允许使用 Round() 和 Truncate())取以下双精度 3.009784654 并将其四舍五入到小数点后 4 位。

这是为了面试,不是为了课堂项目或家庭作业。面试官好像是想让我用mod,但我还是想不出怎么做。

谢谢!

【问题讨论】:

  • 没有 mod,但您可以将其格式化为显示 4 个小数位的字符串并将其解析回双精度数(根本没有效率!)。
  • 是的 - 我向他们提到过,但那也是不允许的!
  • 不开车怎么开车....
  • @HenkHolterman 更像是了解汽车发动机的工作原理,而不是仅仅驾驶它并认为它是理所当然的。

标签: c# rounding


【解决方案1】:

截断(因为未指定舍入规则):乘以 1e4,转换为 int,除以 1e4。

【讨论】:

  • 哦,你是最快的^^
  • 似乎我应该知道这一点(简单的数学) - 但无论出于何种原因我都没有。
  • @AustinSalonen 记录 Math.Round(value, digits) 将 abs(value) 限制为 1e16d。
  • 这不会对数字进行四舍五入,它只会删除 4 之后的数字。在这种情况下,删除的最后 8 会将最后剩下的 7 变成 8。
  • @MrFox 问题中未定义舍入规则,我在回答中明确指出。
【解决方案2】:

这是一个糟糕的面试问题,因为给定预期的工具,该任务通常是不可能的,因为大多数正确的结果都无法表示。也就是说,普通的浮点类型不能准确地表示正确的数学结果 3.0098。所以不可能计算并返回正确的答案。您将不得不使用一些替代机制,例如以不同类型返回值(缩放为整数、字符串、十进制浮点格式等)。

我怀疑面试官可能期待的答案是评估 (int)(x*10000+.5)*.0001。这会缩放该值,以便所需的结果是整数(舍入量 .0001,缩放为 1),添加 0.5,截断为整数,并反转缩放。添加 0.5 和截断的组合几乎等同于舍入,除了它要求 x 为正数、从零开始舍入关系以及存在范围/域问题。可以根据情况和所需的行为对这些进行调整。当然,由于无法表示准确的结果,答案通常略有错误。

一个更有趣的答案是计算 (x*10000+0x1p52-0x1p52)*.0001。这会缩放值,使用当前浮点舍入模式将其舍入为整数,然后撤消缩放。进行四舍五入是因为普通的 double 类型在其有效位中有 53 位,因此,当高位的值为 0x1p52 (252) 时,低位的值为 0x1p0 (20,也称为 1)。为了产生加 0x1p52 的结果,必须对有效位进行四舍五入,这是在浮点硬件中自动完成的。然后减去 0x1p52 删除添加的数字,留下四舍五入的值。和以前一样,范围/域有一些警告,并确保编译器执行双精度算术而不是更多,并且可以进行调整。但是,在某些硬件上它比转换为整数并返回更快。

使用 fmod 或字符串转换性能较差,因为它们需要除法,这在大多数常见处理器上很慢。

【讨论】:

    【解决方案3】:

    乘以 10^numberOfDigitsAfterComma,转换为 int,然后返回 float 并除以 10^...

    double x = 3.009784654;
    x =  ((double)((int)(x * 10000))) / 10000;
    

    【讨论】:

      【解决方案4】:

      如果你真的需要模组,你可以这样做:

      double number = 3.009784654;
      double truncatedNumber = number - number % 0.0001;
      

      【讨论】:

        【解决方案5】:

        使用 mod 的答案:

        double d = 1.23456789;
        int digitsToKeep = 2;
        double divisor = Math.Pow(10, digitsToKeep * -1);
        double rounded = d - (d % divisor);
        

        【讨论】:

          【解决方案6】:

          如果需要,这也会将数字向上取整。

          public static double Round(double number, int digits)
          {
              for (int i = 0; i < digits; i++)
                  number *= 10;
          
              int whole = (int)number;
              double fraction = number - whole;
          
              if (fraction >= 0.5)
                  whole++;
          
              number = whole;
          
              for (int i = 0; i < digits; i++)
                  number /= 10.0;
          
              return number;
          }
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2016-01-23
            • 2014-10-20
            • 2015-01-22
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多