Getting tired of searching for an effective algorithm which calculates the number of digits of a 64-Bit-unsigned-integer but
finding only long-winded binary-to-string-to-binary conversion routines I wrote my own one.
The decimal part uses the coprocessor using this simple formula:
numdigits = int(log(number64))+1
The hexadecimal part uses the powerful BSR ("bit scan reverse") instruction, which can also be considered as binary logarithm.
Input: EAX=Pointer qword ptr
Output: EAX=number of digits
Changed: EAX, EDX, FPU(S0...S2)
Written for TASM, 32Bit.
Thanks for any comments or suggestions.
finding only long-winded binary-to-string-to-binary conversion routines I wrote my own one.
The decimal part uses the coprocessor using this simple formula:
numdigits = int(log(number64))+1
The hexadecimal part uses the powerful BSR ("bit scan reverse") instruction, which can also be considered as binary logarithm.
Input: EAX=Pointer qword ptr
Output: EAX=number of digits
Changed: EAX, EDX, FPU(S0...S2)
Written for TASM, 32Bit.
Thanks for any comments or suggestions.
fpu_ctrlword record fpucw_$1:3,fpucw_ic:1,fpucw_rc:2,fpucw_pc:2,fpucw_ie:1,fpucw_$2:1,fpucw_pm:1,fpucw_um:1,fpucw_om:1,fpucw_zm:1,fpucw_dm:1,fpucw_im:1
;number64 dq 12345678901234
number64 dq 01fh
main proc @type_main argc:dword,argv:dword,argenv:dword
mov eax,offset number64
fninit
;----Start Decimal part----------------------------------------------------------------------------
push dx ;make room for FPU control word
fnstcw ;save FPU control word
push word ptr ;create a copy of FPU control word
setflag word ptr,3 shl fpucw_rc ;set FPU rounding mode: truncate
fldcw ;set the FPU rounding moude
fld1 ;"1"
fldlg2 ;log(2) = 1/log(2,10)
fild qword ptr ;load number64
ftst ;test if number64 equals to zero
fnstsw ax
sahf ;set processor flags to FPU result for evaluation
.if zero?
fcompp ;throw away s0 and s1, leave "1"
.else
fyl2x ;s1 * log(2,s0) = log(2,s0) / log(2,10) = log(s0)
fadd ;= log(s0)+1
.endif
fistp word ptr
xor eax,eax
pop ax ;load EAX with num of digits
fldcw ;restore FPU control word
pop dx ;throw away FPU control word space
;----End Decimal part----------------------------------------------------------------------------
mstr s1,<"The number %I64u contains %d decimal digits.",10>
call printf,offset s1,dword ptr number64+4 dword ptr number64,eax
mov eax,offset number64
;----Start Hexadecimal part----------------------------------------------------------------------------
xor edx,edx ;initialize digit counter value in case number64 equals to zero
bsr edx,dword ptr ;search for the first set bit in HIGH_DWORD
.if zero? ;no bit was set
bsr edx,dword ptr ;search the first set bit in LOW_DWORD
.else
add edx,32
.endif
xchg eax,edx
shr eax,2
inc eax
;----End Hexadecimal part----------------------------------------------------------------------------
mstr s2,<"The number %I64Xh contains %d hexadecimal digits.">
call printf,offset s2,dword ptr number64+4 dword ptr number64,eax
endmain: ret
endp