首页 > 解决方案 > 解释为什么这可以找到两个等于小数点后三位的数字

问题描述

试图理解为什么这段代码可以找到两个等于小数点后三位的数字。

铸造(int)让我措手不及(无法绕开我的头).....

public static boolean areEqualByThreeDecimalPlaces(double firstValue, double secondValue) {
    int moveThreeDecimalPlacesToRight = (int) Math.pow(10, 3);
    return (int) (firstValue * moveThreeDecimalPlacesToRight) == (int) (secondValue * moveThreeDecimalPlacesToRight);
}

标签: java

解决方案


首先请查看规范并了解强制转换表达式的工作原理。

根据该章,这里有一个简短的总结:

  • intValue*doubleValue将是一个double
  • 您可以转换(在这种情况下向下转换)类型,因此(int)(doubleValue * intValue)将被转换为int
  • 如果您明确地将 adouble转换为,int您将丢失小数。

现在让我们逐步分析该代码。

//Just for the example let fisrtValue is 123.456789 and secondValue is 123.456999
double firstValue = 123.456789
double secondValue = 123.456999
(firstValue * moveThreeDecimalPlacesToRight)
// 123.456789 * 1000 will be a double 123456.789
(secondValue * moveThreeDecimalPlacesToRight)
// 123.456999 * 1000 will be a double 123456.999
return 123456.789 == 123456.999 will always return false
(int) (firstValue * moveThreeDecimalPlacesToRight)
// 123.456789 * 1000 will be an int 123456
(int) (secondValue * moveThreeDecimalPlacesToRight)
// 123.456999 * 1000 will be an int 123456

最后

return (int) (firstValue * moveThreeDecimalPlacesToRight) == (int) (secondValue * moveThreeDecimalPlacesToRight);
// return 123456 == 123456 will return true
public static boolean areEqualByThreeDecimalPlaces(double firstValue, double secondValue) {
    // Math.pow(...) retuns a double so it have to downcast to int
    int moveThreeDecimalPlacesToRight = (int) Math.pow(10, 3);
    /* 
     * We don't care about just the first three decimal places
     * If fisrtValue is 123.456789 then 
     * firstValue * moveThreeDecimalPlacesToRight will be 123456.789
     * and secondValue * moveThreeDecimalPlacesToRight will be 123456.999
     * so both of them must be downcasted to int 
     * because 123456.789 will never be equal to 123456.999
    */
    return (int) (firstValue * moveThreeDecimalPlacesToRight) == (int) (secondValue * moveThreeDecimalPlacesToRight);
}

更新

按照@Eritrean 的建议,我不得不提到这是一个非常糟糕的主意。根据转换规范更精确地缩小原始转换部分:

缩小原语转换可能会丢失有关数值整体大小的信息,也可能会丢失精度和范围。

因此,如果您有一个大的 double 数字被向下转换为 int 那么您的方法可以返回误报值。

我刚刚找到了两个(或更多)更好的选择来解决您的问题:


推荐阅读