鉴于代码:
uint Function(uint value)
{
return value * 0x123456D;
}
输入值0x300会产生结果0x69D04700。这只是结果的低32位。 给定结果0x69D04700和因子0x123456D,是否可以检索所有数字(值* 0x123456D)& 0xFFFFFFFF = 0x69D04700快速?
编辑:我显示的代码是伪代码 - 我无法扩大返回类型。
答案 0 :(得分:3)
您需要的是模块化划分,可以使用Euclid算法的版本进行计算。在这种情况下,结果是768。
这是一个非常快的时间(log n ) 2 ,即使对于一个天真的实现。 (如果你需要使用大数字,我可以提供更好的算法参考。)
有关如何实现此目的的草图,请参阅extended Euclidean algorithm。
答案 1 :(得分:0)
好吧,你可以构造一个长值,其中低半部分等于你的结果,高半部分= 1,2,3,4,5 ...除以你的固定乘数,看看你是否得到了一个结果没有余数。通过理解数字中的模式可以略微加快这一点,这样你就可以抛出偶数值或者其他类似值。
但我认为没有明显更少的详尽方法(并且模糊地怀疑这很难做到的事实与某些加密技术有关)。
把这一切都拿回来
import java.io.*;
public class multiply {
public static void main(String[] argv) {
long multiplier = 0x123456DL;
// long result = 0x69D04700L;
long result = (multiplier * 300L) & 0xFFFFFFFFL;
System.out.println("New result = " + Long.toHexString(result));
long offset = (multiplier * 300L) >> 32;
System.out.println("New offset = " + offset);
for (int i = 0; i < 30; i++) {
long test = result + (((i * multiplier) + offset) << 32);
long quotient = test / multiplier;
long remainder = test % multiplier;
System.out.println("Test: " + Long.toHexString(test) + " quotient: " + Long.toHexString(quotient) + " remainder: " + Long.toHexString(remainder));
}
}
}
结果(更正):
C:\JavaTools>java multiply
New result = 55555bbc
New offset = 1
Test: 155555bbc quotient: 12c remainder: 0
Test: 123456e55555bbc quotient: 10000012c remainder: 0
Test: 2468adb55555bbc quotient: 20000012c remainder: 0
Test: 369d04855555bbc quotient: 30000012c remainder: 0
Test: 48d15b555555bbc quotient: 40000012c remainder: 0
Test: 5b05b2255555bbc quotient: 50000012c remainder: 0
Test: 6d3a08f55555bbc quotient: 60000012c remainder: 0
Test: 7f6e5fc55555bbc quotient: 70000012c remainder: 0
Test: 91a2b6955555bbc quotient: 80000012c remainder: 0
Test: a3d70d655555bbc quotient: 90000012c remainder: 0
Test: b60b64355555bbc quotient: a0000012c remainder: 0
Test: c83fbb055555bbc quotient: b0000012c remainder: 0
Test: da7411d55555bbc quotient: c0000012c remainder: 0
Test: eca868a55555bbc quotient: d0000012c remainder: 0
Test: fedcbf755555bbc quotient: e0000012c remainder: 0
Test: 1111116455555bbc quotient: f0000012c remainder: 0
Test: 123456d155555bbc quotient: 100000012c remainder: 0
Test: 13579c3e55555bbc quotient: 110000012c remainder: 0
Test: 147ae1ab55555bbc quotient: 120000012c remainder: 0
Test: 159e271855555bbc quotient: 130000012c remainder: 0
Test: 16c16c8555555bbc quotient: 140000012c remainder: 0
Test: 17e4b1f255555bbc quotient: 150000012c remainder: 0
Test: 1907f75f55555bbc quotient: 160000012c remainder: 0
Test: 1a2b3ccc55555bbc quotient: 170000012c remainder: 0
Test: 1b4e823955555bbc quotient: 180000012c remainder: 0
Test: 1c71c7a655555bbc quotient: 190000012c remainder: 0
Test: 1d950d1355555bbc quotient: 1a0000012c remainder: 0
Test: 1eb8528055555bbc quotient: 1b0000012c remainder: 0
Test: 1fdb97ed55555bbc quotient: 1c0000012c remainder: 0
Test: 20fedd5a55555bbc quotient: 1d0000012c remainder: 0
答案 2 :(得分:0)
如果取0x100000000并除以0x123456D,则得到224.9999(十进制)。这告诉你大约每225个数字,你会击中剩下的数字。当然,因为它不完全是225,所以你不会用整数命中余数。正如@Jacob指出的那样,在32位世界中,你只会遇到一个值(768或0x300)。所以对于这个特定的测试,答案是2 ^ 32 * X + 768,对于所有整数X> = 0。
答案 3 :(得分:0)
是的,这是可能的。
你知道吗
n = 0 (mod 0x123456D)
和
n = 0x69D04700 (mod 0x100000000)
这些是相对素数,因为0x123456D
是奇数而'0x100000000'是2的幂。所以中国剩余定理适用,它给你
n = 0x369D04700 (mod 0x123456D00000000)
这告诉您没有截断的结果是0x369D04700 + k * 0x123456D00000000
。按0x123456D
除以0x300 + k * 0x100000000
。
答案 4 :(得分:0)
你的职能:
uint Function(uint value)
{
return value * 0x123456D;
}
乘以uint
(在所谓的2**64
上下文中的模数为unchecked
的整数)与奇数数相乘。这样的奇数具有唯一的逆,模2**64
。在这种情况下它是0xE2D68C65u
,因为您可以检查(C#语法):
unchecked(0x123456Du * 0xE2D68C65u) == 1u
这种乘法是相关的和可交换的。所以你的“反向”方法是:
uint UndoFunction(uint value)
{
return value * 0xE2D68C65u;
}
(假设unckecked
上下文)。
对于任何输入x
,UndoFunction(Function(x))
和Function(UndoFunction(x))
都会返回原始x
。
PS!为了找到模块化的逆0xE2D68C65u
,我使用了.NET以外的东西。事实上,GP / PARI就像查尔斯一样。在GP中,您可以1/Mod(19088749, 2^32)
或Mod(19088749, 2^32)^-1
。它默认使用十进制表示法。
答案 5 :(得分:-1)
不是您指定的返回类型。如果您希望能够处理64位,则必须将返回类型指定为ulong(或UInt64)。在这种情况下,C#使用严格的静态类型,如果结果无法存储在定义的类型中,则不会自动“上转换”值。即使它进行了upconvert,它也必须退回以提供合法的返回类型,因为在.NET的继承层次结构中,UInt64不是从UInt32派生的。