无心人
发表于 2009-2-4 20:42:34
?
帖子呢?
gxqcn
发表于 2009-2-4 20:44:06
mathe 的代码体现了一种算法思路,
最终的机器代码当然是可以避免跳转的。
那如果是 64 位呢?:Q:
无心人
发表于 2009-2-4 20:53:32
:lol
我在10#给出了一个思路
MMX汇编
如果是64位的,应该还能用SSE
无跳转,无判断
gxqcn
发表于 2009-2-4 21:00:47
感觉还是尽量避免用MMX,
用SIMD指令因更高效,
因为这次不比上次的 UInt64x64To128() 那样需要反复拆包了。
无心人
发表于 2009-2-4 21:04:26
你怎么老排斥MMX啊
不支持 MMX的机器已经不存在了
liangbch
发表于 2009-2-4 21:06:06
我这里给出一个不是用 MMX和XMM指令的版本,使用跳表实现。因为VC中不可以定义标号的地址。故不得不使用汇编文件。
在VC6.0,对于汇编文件,可以自定义build命令,在编译期间同时编译asm文件,为此,你需要
1。安装masm32
2.在VC 中,设置 executable files 目录,指向ml.exe, 比如我的masm32 安装在 c:\masm32,因此executable files目录中添加 C:\masm32\BIN
3. 在VC中,将asm文件添加到project.并选中那个asm文件,设置Custom Build
Commands 框填入:ml /coff /c $(InputPath)
outputs 框填入: $(InputName).obj
下面先给出cpp文件中的测试代码:extern "C" _fastcallint digLen(int n);
void digLenTest()
{
unsigned long n;
n=1;
printf("diglen(%u)=%d\n",n,digLen(n));
n=7;
printf("diglen(%u)=%d\n",n,digLen(n));
n=8;
printf("diglen(%u)=%d\n",n,digLen(n));
n=9;
printf("diglen(%u)=%d\n",n,digLen(n));
n=10;
printf("diglen(%u)=%d\n",n,digLen(n));
n=99;
printf("diglen(%u)=%d\n",n,digLen(n));
n=100;
printf("diglen(%u)=%d\n",n,digLen(n));
n=1000;
printf("diglen(%u)=%d\n",n,digLen(n));
n=9999;
printf("diglen(%u)=%d\n",n,digLen(n));
n=10000;
printf("diglen(%u)=%d\n",n,digLen(n));
n=99999;
printf("diglen(%u)=%d\n",n,digLen(n));
n=100000;
printf("diglen(%u)=%d\n",n,digLen(n));
}再给出汇编文件中的代码:
.486P
.387
OPTION DOTNAME
_TEXT SEGMENT DWORD PUBLIC FLAT 'CODE'
ALIGN 004H
_TEXT ENDS
_DATA SEGMENT DWORD PUBLIC FLAT 'DATA'
ALIGN 004H
_DATA ENDS
_BSS SEGMENT DWORD PUBLIC FLAT 'BSS'
ALIGN 004H
_BSS ENDS
_RDATA SEGMENT DWORD PUBLIC FLAT 'DATA'
ALIGN 004H
_RDATA ENDS
_TEXT1 SEGMENT DWORD PUBLIC FLAT 'CODE'
ALIGN 004H
_TEXT1 ENDS
_DATA1 SEGMENT DWORD PUBLIC FLAT 'DATA'
ALIGN 004H
_DATA1 ENDS
ASSUME CS:FLAT,DS:FLAT,SS:FLAT
_DATA SEGMENT DWORD PUBLIC FLAT 'DATA'
_DATA ENDS
_TEXT SEGMENT DWORD PUBLIC FLAT 'CODE'
ALIGN 4
PUBLIC @digLen@4
@digLen@4 PROC NEAR
test ecx, ecx
jne SHORT L919
xor eax, eax
ret
L919:
bsr eax,ecx
jmp DWORD PTR JTAB_1004
L_012:
mov eax, 1
ret
L_3:
cmp ecx, 10
sbb eax, eax
add eax, 2
ret
L_45:
mov eax, 2
ret
L_6:
cmp ecx, 100
sbb eax, eax
add eax, 3
ret
L_78:
mov eax, 3
ret
L_9:
cmp ecx, 1000
sbb eax, eax
add eax, 4
ret
L936:
mov eax, 4
ret
L938:
cmp ecx, 10000
sbb eax, eax
add eax, 5
ret
L940:
mov eax, 5
ret
L942:
cmp ecx, 100000
sbb eax, eax
add eax, 6
ret
L944:
mov eax, 6
ret
L946:
cmp ecx, 1000000
sbb eax, eax
add eax, 7
ret
L948:
mov eax, 7
ret
L950:
cmp ecx, 10000000
sbb eax, eax
add eax, 8
ret
L952:
mov eax, 8
ret
L954:
cmp ecx, 100000000
sbb eax, eax
add eax, 9
ret
L956:
mov eax, 9
ret
L958:
cmp ecx, 1000000000
sbb eax, eax
add eax, 10
ret
L960:
mov eax, 10
ret
align 4
JTAB_1004:
DD L_012 ;0
DD L_012 ;1
DD L_012 ;2
DD L_3 ;3
DD L_45 ;4
DD L_45 ;5
DD L_6 ;6
DD L_78 ;7
DD L_78 ;8
DD L_9 ;9
DD L936 ;10
DD L936 ;11
DD L936 ;12
DD L938 ;13
DD L940 ;14
DD L940 ;15
DD L942 ;16
DD L944 ;17
DD L944 ;18
DD L946 ;19
DD L948 ;20
DD L948 ;21
DD L948 ;22
DD L950 ;23
DD L952 ;24
DD L952 ;25
DD L954 ;26
DD L956 ;27
DD L956 ;28
DD L958 ;29
DD L960 ;30
DD L960 ;31
ret 0
@digLen@4 ENDP
_TEXT ENDS
END
无心人
发表于 2009-2-4 21:11:21
:L
不懂
liangbch
发表于 2009-2-4 21:15:39
给你一段等价的C代码,你就明白了。
以上的汇编代码即为在编译器编译后的汇编代码的基础上优化(精简)而成.int log2(int n)
{
_asm
{
mov ecx,n
bsr eax,ecx
}
}
extern "C"
_fastcall
int digLen(int n)
{
if (n==0)
return 0;
int c=log2(n);
switch (c)
{
case 0:
case 1:
case 2:
return 1;
case 3:
if (n>=10)
return 2;
else
return 1;
case 4:
case 5:
return 2;
case 6:
if (n>=100)
return 3;
else
return 2;
case 7:
case 8:
return 3;
case 9:
if (n>=1000)
return 4;
else
return 3;
case 10:
case 11:
case 12:
return 4;
case 13:
if (n>=10000)
return 5;
else
return 4;
case 14:
case 15:
return 5;
case 16:
if (n>=100000)
return 6;
else
return 5;
case 17:
case 18:
return 6;
case 19:
if (n>=1000000)
return 7;
else
return 6;
case 20:
case 21:
case 22:
return 7;
case 23:
if (n>=10000000)
return 8;
else
return 7;
case 24:
case 25:
return 8;
case 26:
if (n>=100000000)
return 9;
else
return 8;
case 27:
case 28:
return 9;
case 29:
if (n>=1000000000)
return 10;
else
return 9;
case 30:
case 31:
return 10;
}
}
无心人
发表于 2009-2-4 21:17:13
这么做也可以啊
mov edx, n
xor eax, eax
cmp edx, 1 //1
sbb ecx, ecx
sub eax, ecx
cmp edx, 10//2
sbb ecx, ecx
sub eax, ecx
cmp edx, 100 //3
sbb ecx, ecx
sub eax, ecx
cmp edx, 1000 //4
sbb ecx, ecx
sub eax, ecx
cmp edx, 10000 //5
sbb ecx, ecx
sub eax, ecx
cmp edx, 100000 //6
sbb ecx, ecx
sub eax, ecx
cmp edx, 1000000 //7
sbb ecx, ecx
sub eax, ecx
cmp edx, 10000000 //8
sbb ecx, ecx
sub eax, ecx
cmp edx, 100000000 //9
sbb ecx, ecx
sub eax, ecx
cmp edx, 1000000000 //10
sbb ecx, ecx
sub eax, ecx
gxqcn
发表于 2009-2-4 21:23:13
原帖由 无心人 于 2009-2-4 21:04 发表 http://bbs.emath.ac.cn/images/common/back.gif
你怎么老排斥MMX啊
不支持 MMX的机器已经不存在了
我不是排斥它,而是反感它需要 emms 来擦屁股。
另外用 SIMD 指令一次就可进行4组32位的比较,多么爽啊。:lol