首页 > 解决方案 > 减少和重新扩展 java long 类型

问题描述

我在这里有一个特殊的用例。我目前的任务是将大数字减少270873547828564到较小的数字,并能够从小数字中恢复大数字。为了实现这一点,我实现了两个 java 函数来处理这个任务。下面是函数

 private long reduceLong(long value) {
        return value >> 16;
    }

    private long expandReducedLong(long reduced) {
        return reduced << 16;
    }

现在在我的主要方法中,我调用上面的各个函数,如下所示:

long reduction = reduceLong(270873547828564L);
System.out.println("Reducing 270873547828564 to " + reduction);

long reExpansion = expandReducedLong(reduction);
System.out.println("ReExpanding "+reduction +" to give "+reExpansion);

以下是我控制台中的输出:

Reducing 270873547828564 to give 4133202328
ReExpanding 4133202328 to give 270873547767808

从上面的结果可以看出,60756real large number270873547828564L和 reexpanded value之间存在整差误差270873547767808L。是否有一个技巧可以确保重新扩展总是产生与减少的完全相同的大数字?非常感谢您的时间。

对于我当前的用例,我将大数定义为介于 之间5_000_000_000 and 281474976710655的任何数字,将小数定义为低于或等于5_000_000_000.

标签: java

解决方案


根据您的定义,大数比小数多,因此不可能在它们之间创建一对一的映射。

您可以尝试将一个大数拆分为 2 个小数。

您可能知道, Along使用 64 位表示数字,而int使用 32 位。我们可以将 long 的前 32 位存储到一个int变量中,然后将其他 32 位存储到另一个int变量中。

我们可以通过移位和使用位运算符来做到这一点:

private static int[] splitLargeNumber(long l) {
                       // first 32 bits     the rest 32 bits
    return new int[] { (int)(l >> 32), (int)(l & 0xffffffffL) };
}

private static long combineSmallNumbers(int[] smallNumbers) {
    return ((long)(smallNumbers[0]) << 32) + smallNumbers[1];
}

用法:

long largeNumber = 5_000_000_000L;
int[] smallNumbers = splitLargeNumber(largeNumber);
System.out.println(Arrays.toString(smallNumbers));
System.out.println(combineSmallNumbers(smallNumbers));

如果所有负数都算作小数,则可以进行一对一映射。只需将你的大数减去 281474976710655,你就会得到一个小数。你加 281474976710655,你会得到一个很大的数字。

private long reduceLong(long value) {
    return value - 281474976710655;
}

private long expandReducedLong(long reduced) {
    return reduced + 281474976710655;
}

推荐阅读