【问题标题】:Integer division: How do you produce a double?整数除法:如何产生双精度数?
【发布时间】:2011-03-09 20:18:39
【问题描述】:

对于这个代码块:

int num = 5;
int denom = 7;
double d = num / denom;

d 的值为0.0。可以通过强制转换强制工作:

double d = ((double) num) / denom;

但是还有其他方法可以得到正确的double 结果吗?我不喜欢转换原语,谁知道会发生什么。

【问题讨论】:

  • 将 'int' 转换为 double 是安全的,您将始终获得相同的值而不会损失精度。
  • 我想知道以下是否是编译器为除法所采取的正确步骤:1)将 num 转换为 float 2)将 denom 也转换为 float 2)将 num 除以 denom。如果我不正确,请告诉我。

标签: java casting integer-division


【解决方案1】:
double num = 5;

这避免了演员表。但是您会发现演员转换是明确定义的。您不必猜测,只需检查JLS。 int 到 double 是一个扩大的转换。来自§5.1.2

加宽基元转换不会 失去关于整体的信息 数值的大小。

[...]

int 或 long 值的转换 浮动,或长值 双倍,可能会导致损失 精度——即结果可能会丢失 的一些最低有效位 价值。在这种情况下,结果 浮点值将是 正确舍入的版本 整数值,使用 IEEE 754 四舍五入模式(§4.2.4)

5 可以精确地表示为双精度数。

【讨论】:

  • +1。别再害怕选角了。了解它是如何工作的。这一切都定义明确。
  • @FabricioPH 这适用于各种情况,与 *1.0 解决方案相同。
  • @Saposhiente 它超越了工作与否。更改变量的类型对我来说似乎是肮脏的代码。如果您有一些必须是整数的东西,并且您更改浮点数的表示只是为了能够执行数学运算,那么您可能会冒自己的风险。同样在某些情况下,将变量读取为整数会使代码更容易理解。
  • @FabricioPH,乘以 1.0 仍然会改变结果的类型,只是方式不同。 “对我来说似乎是脏代码”并没有解释在什么情况下您认为乘以 1.0 实际上更好(或者为什么会这样)。
  • @FabricioPH 您和 OP 似乎在错误的信念下工作(您说“更改变量的类型”),即执行 (double)num 会以某种方式改变 num。它没有 - 它为语句的上下文创建一个临时双精度。
【解决方案2】:

转换原语有什么问题?

如果你出于某种原因不想投射,你可以这样做

double d = num * 1.0 / denom;

【讨论】:

  • ...在乘法之前进行隐式转换
  • 在大多数情况下,这比更改其他变量的类型要好。
  • @FabricioPH 没有任何证据表明这是真的,除非你有可以引用的来源。
  • @Saposhiente 在您的其他类似评论中回复
  • 您也可以使用“D”后缀(执行相同的隐式转换); -- 例如:double d = num * 1D / denom;
【解决方案3】:

我不喜欢转换原语,谁知道会发生什么。

为什么你对铸造原语有一种非理性的恐惧?当您将int 转换为double 时,不会发生任何不好的事情。如果您不确定它是如何工作的,请在Java Language Specification 中查找。将int 转换为doublewidening primitive conversion

你可以通过转换分母而不是分子来去掉多余的括号:

double d = num / (double) denom;

【讨论】:

  • 你也可以double d = (double) num / denom;...(好吧,这取决于优先级)
【解决方案4】:

如果你改变一个变量的类型,如果你的公式改变了,你必须记住再次潜入双精度,因为如果这个变量不再是计算的一部分,结果就会混乱。我养成了在计算中强制转换的习惯,并在其旁边添加注释。

double d = 5 / (double) 20; //cast to double, to do floating point calculations

请注意,转换结果不会这样做

double d = (double)(5 / 20); //produces 0.0

【讨论】:

    【解决方案5】:

    Type Casting 是唯一的方法

    可能你不会明确地这样做,但它会发生。

    现在,有几种方法可以尝试获得精确的 double 值(其中 numdenomint 类型,当然使用强制转换)-

    1. 显式转换:
    • double d = (double) num / denom;
    • double d = ((double) num) / denom;
    • double d = num / (double) denom;
    • double d = (double) num / (double) denom;

    但不是double d = (double) (num / denom);

    1. 隐式转换:
    • double d = num * 1.0 / denom;
    • double d = num / 1d / denom;
    • double d = ( num + 0.0 ) / denom;
    • double d = num; d /= denom;

    但不是double d = num / denom * 1.0;
    而不是double d = 0.0 + ( num / denom );


    现在,如果您要问 - 哪个更好?明确的?还是隐含的?

    好吧,我们不要在这里直接回答。请记住——我们程序员不喜欢源代码中的惊喜或魔法。我们真的很讨厌复活节彩蛋。

    另外,额外的操作肯定不会让你的代码更有效率。对吧?

    【讨论】:

    • 浮点数也有效?
    【解决方案6】:

    将整数之一/两个整数强制转换为浮点数以强制使用浮点数学来完成操作。否则整数数学总是首选。所以:

    1. double d = (double)5 / 20;
    2. double v = (double)5 / (double) 20;
    3. double v = 5 / (double) 20;
    

    请注意,转换结果不会这样做。因为第一次除法是按照优先规则完成的。

    double d = (double)(5 / 20); //produces 0.0
    

    我不认为你正在考虑的铸造有任何问题。

    【讨论】:

      【解决方案7】:

      使用类似的东西:

      double step = 1d / 5;
      

      (1d 是加倍)

      【讨论】:

      • 1d 不是演员表,它只是一个声明。
      【解决方案8】:

      最好的办法是

      int i = 3;
      Double d = i * 1.0;
      
      d is 3.0 now.
      

      【讨论】:

        【解决方案9】:

        您可以考虑包装这些操作。例如:

        class Utils
        {
            public static double divide(int num, int denom) {
                return ((double) num) / denom;
            }
        }
        

        这使您可以查看(仅一次)演员是否完全按照您的意愿行事。这种方法也可以接受测试,以确保它继续做你想做的事。您使用什么技巧来导致除法也无关紧要(您可以在此处使用任何答案),只要它产生正确的结果即可。在任何需要将两个整数相除的地方,您现在只需调用 Utils::divide 并相信它会做正确的事。

        【讨论】:

          【解决方案10】:

          就用这个吧。

          int fxd=1;
          double percent= (double)(fxd*40)/100;
          

          【讨论】:

            【解决方案11】:

            只需添加“D”即可。

            int i = 6;
            double d = i / 2D; // This will divide bei double.
            System.out.println(d); // This will print a double. = 3D
            

            【讨论】:

            • 小数后缀.0 通常对人类来说更清楚。 d 是下一个最佳选择。我认为D 是有害的,因为它看起来太像一个数字而不能与数字相邻。
            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2020-12-23
            • 2019-07-13
            • 2016-11-06
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多