【问题标题】:Why does Round(-0.0066219357357) return -1?为什么 Round(-0.0066219357357) 返回 -1?
【发布时间】:2013-02-03 17:37:37
【问题描述】:

我想Round(-0.0066219357357),它给了-1

不应该是0吗?我可以用什么来正确舍入它?

更新: 该数字是 (LineDirection.X/distance) 的结果; 其中 LineDirection.X 是一个整数,而 Distace 是双精度数。

【问题讨论】:

  • 我觉得很奇怪。那将是Ceil()Round 有其他“问题”(它使用银行家的四舍五入)
  • 用 Delphi XE 控制台应用程序测试,没有用:Writeln(Round(-0.0066219357357)); 显示 0!
  • SetRoundMode 设置的不同选项也总是给出0。
  • 嗯。这是一个如此简单的测试用例,我很想说犯错不是一种选择。那么这里有什么不同呢?我是@D2009。
  • 您确定没有意外使用的另一个 Round 函数吗?像这样的一行会给你带来问题:function Round(e: Extended): Extended; begin Result := Trunc(e); end;

标签: delphi


【解决方案1】:

从XE查看System.pas,所有工作都由FISTP指令完成:

    procedure _ROUND;
    asm
      ...
            FISTP   qword ptr [ESP]
      ...
    end;

根据Intel的Instruction Reference,value“被四舍五入为整数值,根据FPU控制字的RC字段指定的舍入方式”

因此,我建议您检查 FPU 控制字的 RC 字段是否设置为您需要的舍入。

您可以通过使用整个控制字来做到这一点 - 请参阅Set8087CW,以及相关的xxxx8087CW 过程/函数,以及Default8087CW 变量。

或者你可以试试Math.SetRoundMode,就像@Uwe Raabe 建议的那样。您的情况听起来像 使用了 rmUp 或 rmTruncate rmDown

从理论上讲,你的 CPU 也可能是原因,但实际上并非如此。

【讨论】:

    【解决方案2】:

    来自 Delphi 帮助:

    Round 的行为可能会受到 Set8087CW 过程或Math.SetRoundMode 函数的影响。

    在 Delphi 2006 中测试,Round 和 Ceil 给出相同的结果:0。

    【讨论】:

    • Ceil() 实际上应该总是产生 0。 Floor() 应该总是产生-1。 Round() 取决于舍入模式,尽管,AFAIK 仅适用于非常接近 -0.5 的值(在一个 ulp -- en.wikipedia.org/wiki/Unit_in_the_last_place 内),它确实不适用于给定的值。它应该总是产生 0,即使是 RoundMode = rmDown(朝向负无穷大)。
    • 经常提到的网站download.oracle.com/docs/cd/E19957-01/806-3568/… 说:When used with the convert to integer operation, round toward - infinity causes the convert to become the floor function, while round toward + infinity is ceiling.。这就解释了为什么在RoundMode = rmDown 时返回-1。
    【解决方案3】:

    您要求人们为您解决问题。所以我可以提供以下想法:

    1. 将除法的值存储在 double 类型的变量中。

      ...
      var
        val : Double;
      begin
       val := Expression1/expression2; // use single step in debugger to evaluate and store
       val := Round(val); // now step over this value.
       ...
      
    2. 使用文字进行测试:

      val := Round(0.006);
      val := Round(-0.006);
      

    观察一致或不一致的结果,检查并发布这些结果。请记住,这里可能会发生很多事情:

    A.涉及哪些类型以及发生了哪些显着性/精度损失?

    B.您的计算中是否有任何整数溢出错误发生在您没有考虑在内的任何地方?

    C.是否有人截断了您没有考虑到的任何结果?

    D.特殊情况下;有人在评论中询问另一个名为 Round() 的函数? CPU问题?内存损坏?创造性地思考,你是一个程序员。在 CPU 视图中打开 Debug-DCU 并单步执行代码。确保进入 System.pas _ROUND。使用调试表达式求值器和调试观察窗口来观察变量值。想办法。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-08-14
      • 2012-01-25
      • 2012-03-05
      • 2017-06-04
      • 2015-01-25
      • 2023-03-27
      相关资源
      最近更新 更多