- iOS/Objective-C 元类和类别
- objective-c - -1001 错误,当 NSURLSession 通过 httpproxy 和/etc/hosts
- java - 使用网络类获取 url 地址
- ios - 推送通知中不播放声音
我的答案来源:
Is this expression correct in C preprocessor
我在这里有点力不从心,我正在尝试了解这种特殊优化的工作原理。
如答案中所述,gcc 将整数除以 7 优化为:
mov edx, -1840700269
mov eax, edi
imul edx
lea eax, [rdx+rdi]
sar eax, 2
sar edi, 31
sub eax, edi
转换回 C 为:
int32_t divideBySeven(int32_t num) {
int32_t temp = ((int64_t)num * -015555555555) >> 32;
temp = (temp + num) >> 2;
return (temp - (num >> 31));
}
我们先来看第一部分:
int32_t temp = ((int64_t)num * -015555555555) >> 32;
为什么是这个数字?
好吧,让我们用 2^64 除以 7,看看会弹出什么。
2^64 / 7 = 2635249153387078802.28571428571428571429
这看起来很乱,如果我们将它转换成八进制呢?
0222222222222222222222.22222222222222222222222
这是一个非常漂亮的重复模式,这肯定不是巧合。我的意思是我们记得 7 是 0b111
并且我们知道,当我们除以 99 时,我们往往会在基数 10 中得到重复模式。因此,当我们在基数 8 中得到重复模式时,这是有道理的我们除以 7。
那么我们的号码从何而来?
(int32_t)-1840700269
等同于(uint_32t)2454267027
* 7 = 17179869189
最后 17179869184 是 2^34
这意味着 17179869189 是 7 2^34 的最接近倍数。或者换句话说,2454267027 是适合 uint32_t
的最大数字,乘以 7 非常接近 2 的幂
这个八进制数是多少?
0222222222223
为什么这很重要?好吧,我们想除以 7。这个数字大约是 2^34/7...。所以如果我们乘以它,然后左移 34 次,我们应该得到一个非常接近精确数字的数字。
最后两行看起来像是为了修补近似误差而设计的。
也许在此领域拥有更多知识和/或专业知识的人可以插话。
>>> magic = 2454267027
>>> def div7(a):
... if (int(magic * a >> 34) != a // 7):
... return 0
... return 1
...
>>> for a in xrange(2**31, 2**32):
... if (not div7(a)):
... print "%s fails" % a
...
失败从 3435973841 开始,有趣的是 0b11001100110011001100110011010001
对近似失败的原因进行分类有点超出我的理解范围,而补丁修复它的原因也是如此。有谁知道魔法是如何运作的?
最佳答案
算法的第一部分是乘以 7 的倒数的近似值。在本例中,我们通过整数乘法和右位移来近似计算倒数。
首先,我们将值 -1840700269
(八进制 -015555555555
)视为 32 位整数。如果将其作为无符号 32 位整数读取,则其值为 2454267027
(八进制 22222222223
)。事实证明,2454267027/2^34
是一个非常接近 1/7
的整数近似值。
为什么我们选择这个数字和 2 的特定次方?我们使用的整数越大,近似值就越接近。在这种情况下,2454267027
似乎是最大的整数(满足上述属性),您可以将其与带符号的 32 位 int 相乘而不会溢出 64 位 int。
接下来,如果我们用 >> 34
立即右移并将结果存储在 32 位 int 中,我们将失去两个最低位的精度。这些位对于确定整数除法的正确底数是必需的。
我不确定第二行是否从 x86 代码翻译正确。那时,temp
大约是 num * 4/7
,所以 num * 4/7 + num
到那个位置,位移就开始了给你大约 num * 1/7 + num * 1/4
,这是一个相当大的错误。
例如,输入 57,其中 57//7 = 8
。我也在代码中验证了以下内容:
57 * 2454267027 = 139893220539
139893220539 >> 32 = 32
(此时大约 57 * 4/7 = 32.5714...
)32 + 57 = 89
89 >> 2 = 22
(哈??此时离 8
还很远。)不管怎么说,最后一行,是我们这样计算有符号整数除法后做的调整。我引用 Hacker's delight on signed division 的部分:
The code most naturally computes the floor division result, so we need a correction to make it compute the conventional truncated toward 0 result. This can be done with three computational instructions by adding to the dividend if the dividend is negative.
在这种情况下(引用你的另一篇文章)你似乎在做一个有符号的转变,所以它会在负数的情况下减去 -1
;给出 +1
的结果。
这甚至不是您能做的全部;这是一个更疯狂的blog post about how to divide by 7 with just a single multiplication .
关于algorithm - 整数除以 7,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15262472/
你有没有注意到 Excel Vba 代码中除法 2/60 的问题?我正在使用 Excel 2013。请测试以下代码: Sub test1() Dim A As Integer Dim B As Int
我正在运行长时间的模拟。我将结果记录到 vector 中以计算有关数据的统计信息。我意识到,理论上,这些样本可能是除以零的结果。这只是理论上的,我很确定事实并非如此。为了避免修改代码后重新运行模拟,我
我有一些可以包含字母、数字和“#”符号的字符串。 我想删除除以“#”开头的单词以外的数字 下面是一个例子: "table9 dolv5e #10n #dec10 #nov8e 23 hello" 预期
我有以下代码,问题是我尝试将 Double 除以 Int factorial :: Int -> Int factorial 0 = 1 factorial e = e * (factorial e-
我有以下查询,它试图计算出某种产品占产品总数的百分比。 IE:[产品数量]/[产品总数] = 百分比 ;WITH totalCount AS( SELECT CAST(COUN
我正在解析字符串,然后需要将其转换为数字。但如果它包含除以 0 的例子 String str1 = "1+2+3-5/0+4+6" String str2 = "1+2+3-4/0.000 +4+6"
这个问题已经有答案了: Right Shift to Perform Divide by 2 On -1 (6 个回答) 已关闭 9 年前。 在阅读 Collections.reverse 的 Jav
我是 C++ 新手。我听说除以0会导致运行时错误,但是当我尝试时,它抛给我一个编译器错误C2124并且没有创建目标文件,所以编译器会自动运行代码以查看它是否可以在创建之前执行目标文件? (顺便说一句,
我试图在 codefights.com 上解决这个问题,方法是找出最大的质因数并将该数字除以质因数的幂。 int highestPower(int N, int A) { int B =A, j=0,
我对在不同计算机上运行程序有疑问。 我用 C++\windows 7 64 位\Visual Studio 编写了一个程序,该程序在我的计算机上完美运行。 当我尝试在另一台计算机(Windows 7
这个问题已经有答案了: Division in C++ not working as expected (6 个回答) 已关闭 9 年前。 Helo,我是编程新手,遇到了一个问题,我有一个整数,例如
我正在做某事,但遇到了一个我不明白的问题。 double d = 95.24 / (double)100; Console.Write(d); //Break point here 控制台输出是 0.
我需要仅使用按位运算符(例如 ! & ^ ~ 和移位)来计算数字 (a/(2**b)。我得到了以下提示,但我是 C 新手,我不知道什么是代码含义: int bias = x>0 ? 0 : ((1>b
这个问题在这里已经有了答案: 关闭 10 年前。 Possible Duplicate: Java Integer division: How do you produce a double? 当我
嗨,我正在尝试将 numpy 数组分成两部分,并在一个循环中进行此操作,例如: main_array.shape = (50, 400, 400, 3) for i = 0: sub_array_1
这是片段: String myTime = someTime / 1e9d + ","; someTime 是使用 System.nanoTime() 派生的。 1e9d 在这里做什么? 最佳答案 1
Random random = new Random(); int randomx = random.Next(0, 240); 这是我获取随机数的方式,从 0 到 240,如何才能只获取除以 5 的
我一直在处理一个应用程序,因为图像表现得很奇怪,所以我决定打开 Wall 标志,看看是否有任何奇怪的事情发生。它揭示了一个新的警告: character.cpp(364): warning C4723
我是 Android Studio 的新手,我正在开发一个计算器应用程序。现在,当我除以零时,自然会收到错误消息“Infinity”,但如果我想将其更改为“不能除以零”,我该怎么做呢? impor
如何显示每 5 日创建一个新行的表中的数据 ? 例子 data: [1,2,3,4,5,6]; 成分: {{item}} 预期的: | 1 | 2 | 3 | 4 | 5 | | 6 |
我是一名优秀的程序员,十分优秀!