- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
对于我的 BigInteger 代码,对于非常大的 BigIntegers,输出速度很慢。所以现在我使用递归分治算法,仍然需要 2'30"将当前最大的已知素数转换为超过 2200 万位的十进制字符串(但将其转换为十六进制字符串只需要 135 ms) .
我仍然想减少时间,所以我需要一个可以非常快速地将 NativeUInt(即 32 位平台上的 UInt32,64 位平台上的 UInt64)除以 100 的例程。所以我使用乘以常数。这在 32 位代码中工作得很好,但我不能 100% 确定在 64 位代码中。
所以我的问题是:有没有办法检查无符号 64 位值与常量相乘结果的可靠性?我通过简单地尝试 UInt32 (0..$FFFFFFFF) 的所有值来检查 32 位值。这大约需要。 3分钟。检查所有 UInt64 将花费比我一生更长的时间。有没有办法检查所使用的参数(常数、移位后)是否可靠?
我注意到,如果所选参数错误(但接近),对于像 $4000004B
这样的值,DivMod100()
总是会失败。是否有特殊值或范围来检查 64 位,以便我不必检查所有值?
我当前的代码:
const
{$IF DEFINED(WIN32)}
// Checked
Div100Const = UInt32(UInt64($1FFFFFFFFF) div 100 + 1);
Div100PostShift = 5;
{$ELSEIF DEFINED(WIN64)}
// Unchecked!!
Div100Const = $A3D70A3D70A3D71;
// UInt64(UInt128($3 FFFF FFFF FFFF FFFF) div 100 + 1);
// UInt128 is fictive type.
Div100PostShift = 2;
{$IFEND}
// Calculates X div 100 using multiplication by a constant, taking the
// high part of the 64 bit (or 128 bit) result and shifting
// right. The remainder is calculated as X - quotient * 100;
// This was tested to work safely and quickly for all values of UInt32.
function DivMod100(var X: NativeUInt): NativeUInt;
{$IFDEF WIN32}
asm
// EAX = address of X, X is UInt32 here.
PUSH EBX
MOV EDX,Div100Const
MOV ECX,EAX
MOV EAX,[ECX]
MOV EBX,EAX
MUL EDX
SHR EDX,Div100PostShift
MOV [ECX],EDX // Quotient
// Slightly faster than MUL
LEA EDX,[EDX + 4*EDX] // EDX := EDX * 5;
LEA EDX,[EDX + 4*EDX] // EDX := EDX * 5;
SHL EDX,2 // EDX := EDX * 4; 5*5*4 = 100.
MOV EAX,EBX
SUB EAX,EDX // Remainder
POP EBX
end;
{$ELSE WIN64}
asm
.NOFRAME
// RCX is address of X, X is UInt64 here.
MOV RAX,[RCX]
MOV R8,RAX
XOR RDX,RDX
MOV R9,Div100Const
MUL R9
SHR RDX,Div100PostShift
MOV [RCX],RDX // Quotient
// Faster than LEA and SHL
MOV RAX,RDX
MOV R9D,100
MUL R9
SUB R8,RAX
MOV RAX,R8 // Remainder
end;
{$ENDIF WIN32}
最佳答案
像往常一样,在编写优化代码时,使用编译器输出作为提示/起点。可以安全地假设它所做的任何优化在一般情况下都是安全的。错误代码编译器错误很少见。
gcc 实现了无符号 64 位 divmod,常量为 0x28f5c28f5c28f5c3
。我还没有详细研究生成除法常量,但是有一些生成它们的算法可以给出已知的良好结果(因此不需要详尽的测试)。
该代码实际上有一些重要的区别:它使用的常量与 OP 的常量不同。
请参阅评论来分析它实际上在做什么:首先除以 4,因此它可以使用一个仅适用于当被除数足够小时除以 25 的常量。这也避免了以后需要添加。
#include <stdint.h>
// rem, quot ordering takes one extra instruction
struct divmod { uint64_t quotient, remainder; }
div_by_100(uint64_t x) {
struct divmod retval = { x%100, x/100 };
return retval;
}
compiles to (gcc 5.3 -O3 -mtune=haswell
) :
movabs rdx, 2951479051793528259
mov rax, rdi ; Function arg starts in RDI (SysV ABI)
shr rax, 2
mul rdx
shr rdx, 2
lea rax, [rdx+rdx*4] ; multiply by 5
lea rax, [rax+rax*4] ; multiply by another 5
sal rax, 2 ; imul rax, rdx, 100 is better here (Intel SnB).
sub rdi, rax
mov rax, rdi
ret
; return values in rdx:rax
使用“二进制”选项查看十六进制常量,因为反汇编器输出就是这样做的,这与 gcc 的 asm 源输出不同。
<小时/>gcc 使用上述 lea/lea/shl 序列,与您的问题中的相同。您的答案是使用 mov imm
/mul
序列。
你们的评论都说他们选择的版本更快。如果是这样,那是因为一些微妙的指令对齐或其他次要影响:在 Intel SnB 系列上,它是 the same number of uops (3) ,以及相同的关键路径延迟(mov imm
不在关键路径上,mul
为 3 个周期)。
clang uses我认为最好的选择(imul rax, rdx, 100
)。在看到 clang 选择它之前我就想到了这一点,但这并不重要。那是 1 个融合域 uop(只能在 p0 上执行),仍然具有 3c 延迟。因此,如果您使用此例程进行多精度处理时受到延迟限制,它可能不会有帮助,但它是最好的选择。 (如果您受到延迟限制,将代码内联到循环中而不是通过内存传递参数之一可以节省大量周期。)
imul
之所以有效,是因为 you're only using the low 64b of the result 。 mul
不存在 2 或 3 个操作数形式,因为无论输入的有符号或无符号解释如何,结果的低半部分都是相同的。
顺便说一句,带有 -march=native
的 clang 使用 mulx
表示 64x64->128,而不是 mul
,但没有增益任何东西。根据 Agner Fog 的表格,它的延迟比 mul
差一个周期。
AMD 对于 imul r,r,i
(尤其是 64b 版本)的延迟比 3c 还要差,这也许就是 gcc 避免使用它的原因。我不知道 gcc 维护者在调整成本上投入了多少工作,因此像 -mtune=haswell
这样的设置工作良好,但是很多代码不是用任何 -mtune 编译的
设置(即使是 -march
隐含的设置),因此当 gcc 做出最适合旧 CPU 或 AMD 的选择时,我并不感到惊讶。
clang 仍然使用 imul r64, r64, imm
和 -mtune=bdver1
(Bulldozer),这可以节省 m-ops,但比使用多 1c 延迟为代价lea/lea/shl. (在 Bulldozer 上,比例>1 的 lea 延迟为 2c)。
关于delphi - 检查 64 位常数乘法参数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35100712/
我不明白基因编程的人工智能是如何实现的。可以确定最终方程中何时应该有一个常数。如果我采用公式 F(m) = ma; F(m) = m9.8,A.I.知道真正的数字 9.8 到底是多少吗?据我了解,您实
我的批次大小是可变的,所以我的所有输入都是以下形式 tf.placeholder(tf.float32, shape=(None, ...) 接受可变的批量大小。但是,如何创建具有可变批处理大小的常数
我有一个一维 Numpy 数组 A长度N .对于每个元素 x在数组中,我想知道数组中所有元素在[x-eps]范围内的比例是多少; x+eps ],其中 eps是一个常数。 N数量级为 15,000。
如果我像这样在文件中设置一些常量: 'use strict'; angular.module('balrogApp.config', []) .constant('balrogConfig',
谁能给我一个常量 r 值的例子? 因为显然即使文字也是右值而不是常量右值。 最佳答案 const T f(); 根据该定义,表达式 f() 是 const T 类型的右值表达式,即常量右值。 关于c+
我正在开发一个 Angular 应用程序,我想创建一个配置文件。根据我的阅读,我应该使用 Angular 常数。 所以我尝试创建我的常量。从我读到的内容( here , here 以及 here +
const int N = 100; void function1(int array[]){ // ... } void function2(int arra
考虑以下(工作)片段: Eigen::ArrayXd x (8); x > y (x.data(), 2, 4); 这也是可行的: const Eigen::ArrayXd const_x = x;
我知道你可以使用: #define _USE_MATH_DEFINES 然后: M_PI 得到常量 pi。但是,如果我没记错的话(欢迎评论)这是编译器/平台相关的。那么,当我将 pi 常量从 Linu
为什么这段代码无法编译? package main const a = 1.000001 const base = 0 const b = a+base func main() { f(b)
为什么下面的代码每条语句都引用了大O常量(这里我为了约定使用1)? 我的意思是,如果数组大小变大,时间复杂度可能会变大,对吗?而且总数会越来越大,会不会影响复杂度? 伪代码: def find_sum
我正在尝试创建一个函数来填充多个系列中缺失的数字,具有不同的数字比例,同时为每个系列生成一个常量列。 from tika import parser import pandas as pd impor
我正在尝试近似 e 的值(~2.7) 由此定义,对于每个第 n 项 在Python中使用递归函数。 到目前为止我已经得到了这个, def NapierConstant(runs): retur
系统提示我输入代码以某种方式打印 Champerowne 常量系列。 (实际使用它!)所以我们想找到这个系列的第 n 个数字:1234567891011121314...这是我的代码: #inclu
我正在学习硕士定理的期中考试,我遇到了案例 2 的示例,其中 k > 0。除了常数及其递增或计算方式之外,我了解有关定理的所有内容。 Case 2状态:T(n) = Θ(nlogba logk+1n)
问题实例:无向无权图 G=(V,E)。两个源节点a和b,两个目的节点c和d以及一个常数D(完全正数)。(我们可以假设lambda(c,d),lambda(a,b)>D,当lambda(x,y ) 是
我有一张很大的 table 。 它目前在 MySQL 数据库中。 我使用django。 我需要迭代 每个表的元素来预先计算一些特定的数据(也许如果我更好的话,我可以这样做,但这不是重点)。 我想在不断
VBScript 常数 常数是具有一定含义的名称,用于代替数字或字符串,其值从不改变。VBScript 定义了许多内部常数。详细信息,请参阅 VBScript 语言参考。 创建常数 您可以使用
我正在学习 javascript,我发现一个文件中有许多用操作数“:”而不是“=”完成的赋值。尽管问题的标题是这样,但我也在非常量中看到过它。那有什么意义呢?这里的“:”操作数是什么意思?谢谢。 v
鉴于应用程序启动: angular.module("starter", [ "ionic" ]) .constant("DEBUG", true) .run(function() {
我是一名优秀的程序员,十分优秀!