- iOS/Objective-C 元类和类别
- objective-c - -1001 错误,当 NSURLSession 通过 httpproxy 和/etc/hosts
- java - 使用网络类获取 url 地址
- ios - 推送通知中不播放声音
我需要做以下算术:
long a,b,c;
long result = a*b/c;
虽然结果保证适合 long
,但乘法不是,所以它可能会溢出。
我试着一步一步地做(先乘后除),同时通过将 a*b
的中间结果拆分成一个最大为 4 的 int 数组( much就像 BigInteger 正在使用它的 int[] mag
变量一样)。
在这里,我被部门困住了。我无法理解进行精确除法所需的位移位。我只需要商(不需要余数)。
假设的方法是:
public static long divide(int[] dividend, long divisor)
此外,我不考虑使用 BigInteger
,因为这部分代码需要快速(我想坚持使用基元和基元数组)。
如有任何帮助,我们将不胜感激!
编辑:我并不想自己实现整个 BigInteger
。我想做的是比使用通用 BigInteger< 更快地解决特定问题(
.a*b/c
,其中 a*b
可能溢出)/
Edit2:如果能以一种聪明的方式完成,那将是理想的,完全不会溢出,评论中出现了一些提示,但我仍在寻找正确的.
更新:我尝试将 BigInteger 代码移植到我的特定需求,而不创建对象,并且在第一次迭代中,与使用 BigInteger(在我的开发电脑上)相比,我的速度提高了约 46%。
然后我尝试了一些修改过的@David Eisenstat 解决方案,这让我减少了 ~56%(我从 Long.MIN_VALUE
到 Long.MAX_VALUE
运行了 100_000_000_000 个随机输入)与 BigInteger 相比,运行时间(超过 2 倍)(与我采用的 BigInteger 算法相比,大约是 18%)。
还会有更多的优化和测试迭代,但在这一点上,我认为我必须接受这个答案是最好的。
最佳答案
我一直在修补一种方法,即 (1) 将 a
和 b
与 21 位肢体上的学校算法相乘 (2) 进行长除法通过 c
,残差 a*b - c*q
的不寻常表示使用 double
来存储高阶位和一个 long
来存储低位。我不知道它是否可以与标准长除法竞争,但为了您的享受,
public class MulDiv {
public static void main(String[] args) {
java.util.Random r = new java.util.Random();
for (long i = 0; true; i++) {
if (i % 1000000 == 0) {
System.err.println(i);
}
long a = r.nextLong() >> (r.nextInt(8) * 8);
long b = r.nextLong() >> (r.nextInt(8) * 8);
long c = r.nextLong() >> (r.nextInt(8) * 8);
if (c == 0) {
continue;
}
long x = mulDiv(a, b, c);
java.math.BigInteger aa = java.math.BigInteger.valueOf(a);
java.math.BigInteger bb = java.math.BigInteger.valueOf(b);
java.math.BigInteger cc = java.math.BigInteger.valueOf(c);
java.math.BigInteger xx = aa.multiply(bb).divide(cc);
if (java.math.BigInteger.valueOf(xx.longValue()).equals(xx) && x != xx.longValue()) {
System.out.printf("a=%d b=%d c=%d: %d != %s\n", a, b, c, x, xx);
}
}
}
// Returns truncate(a b/c), subject to the precondition that the result is
// defined and can be represented as a long.
private static long mulDiv(long a, long b, long c) {
// Decompose a.
long a2 = a >> 42;
long a10 = a - (a2 << 42);
long a1 = a10 >> 21;
long a0 = a10 - (a1 << 21);
assert a == (((a2 << 21) + a1) << 21) + a0;
// Decompose b.
long b2 = b >> 42;
long b10 = b - (b2 << 42);
long b1 = b10 >> 21;
long b0 = b10 - (b1 << 21);
assert b == (((b2 << 21) + b1) << 21) + b0;
// Compute a b.
long ab4 = a2 * b2;
long ab3 = a2 * b1 + a1 * b2;
long ab2 = a2 * b0 + a1 * b1 + a0 * b2;
long ab1 = a1 * b0 + a0 * b1;
long ab0 = a0 * b0;
// Compute a b/c.
DivBy d = new DivBy(c);
d.shift21Add(ab4);
d.shift21Add(ab3);
d.shift21Add(ab2);
d.shift21Add(ab1);
d.shift21Add(ab0);
return d.getQuotient();
}
}
public strictfp class DivBy {
// Initializes n <- 0.
public DivBy(long d) {
di = d;
df = (double) d;
oneOverD = 1.0 / df;
}
// Updates n <- 2^21 n + i. Assumes |i| <= 3 (2^42).
public void shift21Add(long i) {
// Update the quotient and remainder.
q <<= 21;
ri = (ri << 21) + i;
rf = rf * (double) (1 << 21) + (double) i;
reduce();
}
// Returns truncate(n/d).
public long getQuotient() {
while (rf != (double) ri) {
reduce();
}
// Round toward zero.
if (q > 0) {
if ((di > 0 && ri < 0) || (di < 0 && ri > 0)) {
return q - 1;
}
} else if (q < 0) {
if ((di > 0 && ri > 0) || (di < 0 && ri < 0)) {
return q + 1;
}
}
return q;
}
private void reduce() {
// x is approximately r/d.
long x = Math.round(rf * oneOverD);
q += x;
ri -= di * x;
rf = repairLowOrderBits(rf - df * (double) x, ri);
}
private static double repairLowOrderBits(double f, long i) {
int e = Math.getExponent(f);
if (e < 64) {
return (double) i;
}
long rawBits = Double.doubleToRawLongBits(f);
long lowOrderBits = (rawBits >> 63) ^ (rawBits << (e - 52));
return f + (double) (i - lowOrderBits);
}
private final long di;
private final double df;
private final double oneOverD;
private long q = 0;
private long ri = 0;
private double rf = 0;
}
关于java - (a * b)/c MulDiv 和处理中间乘法溢出,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54232987/
如果矩阵A在X中,矩阵B在Y中。 进行乘法运算只是 Z = X*Y。正确假设两个数组的大小相同。 如何使用 for 循环计算它? 最佳答案 ja72 的anwser 是错误的,请查看我在其下的评论以了
我有一个 C 程序,它有 n 次乘法(单次乘法和 n 次迭代),我发现另一个逻辑有 n/2 次迭代(1 次乘法 + 2 次加法)。我知道两者都是 O(n) 的复杂性。但就 CPU 周期而言。哪个更快?
我有一个矩阵x: x <- matrix(1:8, nrow = 2, ncol = 4, byrow = 2) # [,1] [,2] [,3] [,4] #[1,] 1 2 3
我有一个矩阵x: x <- matrix(1:8, nrow = 2, ncol = 4, byrow = 2) # [,1] [,2] [,3] [,4] #[1,] 1 2 3
我正在创建一个基于电影 InTime 的 Minecraft 插件,并尝试创建代码,在玩家死亡时玩家将失去 25% 的时间。 当前代码是: String minus = itapi.getTimeSt
我正在尝试将 2 个矩阵与重载的 * 运算符相乘并打印结果。虽然看起来我不能为重载函数提供超过 1 个参数。如何将这两个矩阵传递给重载函数?请在下面查看我的实现。 #include #include
为什么在 Java 中使用 .*?例如 double probability = 1.*count/numdata; 给出相同的输出: double probability = count/numda
如果我尝试将两个值与单位相乘,则会出现意外错误。 $test: 10px; .testing{ width: $test * $test; } result: 100px*px isn't a v
我正在尝试计算库存中所有产品的总值(value)。表中的每种产品都有价格和数量。因此,我需要将每种产品的价格乘以数量,然后将所有这些加在一起以获得所有产品的总计。根据上一个问题,我现在可以使用 MyS
我正在尝试计算库存中所有产品的总值(value)。表中的每种产品都有价格和数量。因此,我需要将每种产品的价格乘以数量,然后将所有这些加在一起以获得所有产品的总计。根据上一个问题,我现在可以使用 MyS
大家好,我有以下代码行 solution first = mylist.remove((int)(Math.random() * mylist)); 这给了我一个错误说明 The operator *
我必须做很多乘法运算。如果我考虑效率,那么我应该使用位运算而不是常规的 * 运算吗?如果有差异如何进行位运算?提前致谢.. 最佳答案 不,您应该使用乘法运算符,让优化编译器决定如何最快地完成它。 您会
两个 n 位数字 A 和 B 的乘法可以理解为移位的总和: (A << i1) + (A << i2) + ... 其中 i1, i2, ... 是 B 中设置为 1 的位数。 现在让我们用 OR
我想使用 cuda 6 进行 bool 乘法,但我无法以正确的方式做到这一点。B 是一个 bool 对称矩阵,我必须进行 B^n bool 乘法。 我的 C++ 代码是: for (m=0; m
我正在编写一个定点类,但遇到了一些问题...乘法、除法部分,我不确定如何模拟。我对部门运算符(operator)进行了非常粗暴的尝试,但我确信这是错误的。到目前为止,它是这样的: class Fixe
我有TABLE_A我需要创建 TABLE_A_FINAL 规则: 在TABLE_A_FINAL中我们有包含 ID_C 的所有可能组合的行如果在 TABLE_A与 ID_C 的组合相同我们乘以 WEIG
这个问题在这里已经有了答案: Simple way to repeat a string (32 个答案) 关闭 6 年前。 我有一个任务是重复字符乘以它例如用户应该写重复输入 3 R 输出的字母和
我最近学习了C++的基础知识。我发现了一些我不明白的东西。这是让我有点困惑的程序。 #include using namespace std; int main()
我有两个列表: list_a = list_b = list(范围(2, 6)) final_list = [] 我想知道如何将两个列表中的所有值相乘。我希望我的 final_list 包含 [2*2
如何修改此代码以适用于任何基数? (二进制、十六进制、基数 10 等) int mult(int a, int b, int base){ if((a<=base)||(b<=base)){
我是一名优秀的程序员,十分优秀!