如何将double转换为long而不使用强制转换?

212

最佳方式将double转换为long而不使用强制类型转换是什么?

例如:

double d = 394.000;
long l = (new Double(d)).longValue();
System.out.println("double=" + d + ", long=" + l);

2
请确保不要使用超过2 ^ 54的双精度浮点数,否则数字将无法适应fraction,因此例如myLong == (long)(myDouble + 1)这样的表达式,其中myLong等于myDouble,将计算为true - Vitalii Fedorenko
这个方法(Double.longValue();)仍然有用,如果你有来自像这样的arraylist ArrayList<Double> 的双精度值,因为你会得到一个无法转换的错误。我只是为那些遇到略微不同问题的人提供这个信息。 - SARose
9个回答

275

假设您希望将值朝零截断,只需进行强制转换:

double d = 1234.56;
long x = (long) d; // x = 1234

这将比通过包装类更快 - 更重要的是,更易读。现在,如果您需要四舍五入到除“向零取整”之外的其他数字,您将需要稍微复杂一些的代码。

8
好的回答 - "朝向零" 的部分对我的应用程序来说是错误的,所以感谢你在回答中强调了这一点,并提醒我不要只进行强制类型转换,而应该在这里使用 Math.round() 。 - Phantomwhale

145

... 这里是四舍五入的方式,它不会截断。赶紧在Java API手册中查找:

double d = 1234.56;
long x = Math.round(d); //1235

它不会像强制转换一样给出相同的结果。因此,这取决于Rich想要做什么。 - Cyrille Ka
3
好的,我会尽力进行翻译。这句话的意思是:“是的,它被视为对Jon所说的内容的补充。” - Johannes Schaub - litb
2
我喜欢这个,因为它也适用于Double和Long对象,而不仅仅是原始类型。 - themanatuf

70

首选方法应该是:

Double.valueOf(d).longValue()

根据Java 平台 SE 7 Double文档:

Double.valueOf(d)

返回表示指定的double值的Double实例。 如果不需要创建新的Double实例,则通常应优先使用此方法而不是构造函数Double (double), 因为该方法通过缓存经常请求的值,可能会在空间和时间性能方面产生显着的改进。


这比已接受的答案更方便。 - DJphy

37

(new Double(d)).longValue() 内部只是进行了类型转换,所以没有必要创建一个 Double 对象。


14

Guava Math库有一种专门设计用于将double转换为long的方法:

long DoubleMath.roundToLong(double x, RoundingMode mode)

您可以使用java.math.RoundingMode指定舍入行为。


7
如果您有强烈的怀疑DOUBLE实际上是LONG类型,并且您想要:
1) 获取其精确值作为LONG类型
2) 当不是LONG类型时抛出错误
您可以尝试以下方法:
public class NumberUtils {

    /**
    * Convert a {@link Double} to a {@link Long}.
    * Method is for {@link Double}s that are actually {@link Long}s and we just
    * want to get a handle on it as one.
    */
    public static long getDoubleAsLong(double specifiedNumber) {
        Assert.isTrue(NumberUtils.isWhole(specifiedNumber));
        Assert.isTrue(specifiedNumber <= Long.MAX_VALUE && specifiedNumber >= Long.MIN_VALUE);
        // we already know its whole and in the Long range
        return Double.valueOf(specifiedNumber).longValue();
    }

    public static boolean isWhole(double specifiedNumber) {
        // https://dev59.com/h2Qo5IYBdhLWcg3wiv7A
        return (specifiedNumber % 1 == 0);
    }
}

Long是Double的子集,所以如果您无意中尝试将超出Long范围的Double转换,可能会得到一些奇怪的结果:

@Test
public void test() throws Exception {
    // Confirm that LONG is a subset of DOUBLE, so numbers outside of the range can be problematic
    Assert.isTrue(Long.MAX_VALUE < Double.MAX_VALUE);
    Assert.isTrue(Long.MIN_VALUE > -Double.MAX_VALUE); // Not Double.MIN_VALUE => read the Javadocs, Double.MIN_VALUE is the smallest POSITIVE double, not the bottom of the range of values that Double can possible be

    // Double.longValue() failure due to being out of range => results are the same even though I minus ten
    System.out.println("Double.valueOf(Double.MAX_VALUE).longValue(): " + Double.valueOf(Double.MAX_VALUE).longValue());
    System.out.println("Double.valueOf(Double.MAX_VALUE - 10).longValue(): " + Double.valueOf(Double.MAX_VALUE - 10).longValue());

    // casting failure due to being out of range => results are the same even though I minus ten
    System.out.println("(long) Double.valueOf(Double.MAX_VALUE): " + (long) Double.valueOf(Double.MAX_VALUE).doubleValue());
    System.out.println("(long) Double.valueOf(Double.MAX_VALUE - 10).longValue(): " + (long) Double.valueOf(Double.MAX_VALUE - 10).doubleValue());
}

“Long是Double的子集”不准确。Long的有效数字位数比Double更多,因此将Long转换为Double时可能会丢失一些信息。例如= https://tio.run/##dY3BCoJAEIbP@hSDECjU0j06eOimJymCiNhcldVxV9xRiPDZt5G6dprh/2a@v5Wz3NmhMq3qvB@mJ@oSSpTOQS61gXcY/EJHknjMVivoGcUFjdo0tzvIsXHJehmgNQ0gwhEy3kSeXh@XNDufDsyUZU8FSjFFXJPi5ajqhZ1IDKwiNDFi8od820Rtx15SHG3Evo62bEvWhyVcvP8A - Thariq Nugrohotomo
@ThariqNugrohotomo double 可以存储比 long 更广泛的数字信息。请查看此网站上关于 longdouble 的部分。 - Tech Expert Wizard

5

只需按照以下步骤:

double d = 394.000;
long l = d * 1L;

1

最好使用new BigDecimal(s).longValue()

这是我的测试,s是一个长整型值的原始字符串,有时以.0结尾

将double强制转换为long((long) DoubleValue)或使用Double.longValue()有时会丢失1(为什么?)。

https://dev59.com/PGoy5IYBdhLWcg3wJKkq#8754567

1651465142958862337, s
1.65146514295886234E18, Double.parseDouble(s)
1.65146514295886234E18, Double.valueOf(s)
1651465142958862340, String.format("%.0f", Double.parseDouble(s)).split("\\.")[0]
1651465142958862336, (long) Double.parseDouble(s)
1651465142958862336, Double.valueOf(s).longValue()
1651465142958862336, Math.round(Double.parseDouble(s))
1651465142958862337, new BigDecimal(s).longValue()  // correct


1.651465142958862337E18, s
1.65146514295886234E18, Double.parseDouble(s)
1.65146514295886234E18, Double.valueOf(s)
1651465142958862340, String.format("%.0f", Double.parseDouble(s)).split("\\.")[0]
1651465142958862336, (long) Double.parseDouble(s)
1651465142958862336, Double.valueOf(s).longValue()
1651465142958862336, Math.round(Double.parseDouble(s))
1651465142958862337, new BigDecimal(s).longValue()  // correct

0
简单来说,强制类型转换比创建Double对象更高效。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接