- Код: Выделить всё
Option Explicit
Private Declare Function allmul Lib "ntdll" _
Alias "_allmul" ( _
ByVal cMultiplicand As Currency, _
ByVal cMultiplier As Currency) As Currency
Private Declare Function alldiv Lib "ntdll" _
Alias "_alldiv" ( _
ByVal cDivident As Currency, _
ByVal cDivisor As Currency) As Currency
Private Sub Form_Load()
Debug.Print alldiv(5, 0.08) ' // 50000 / 800 = 62
Debug.Print allmul(500, 8) ' // 5000000 * 80000 = 400000000000
End Sub
Проблема функции _allmul в том что она не сигнализирует о переполнении, для этого я написал 2 функции mul64 и imul64 которые выполняют соответствующее умножение беззнаковых и знаковых 64 битных целы, а также сигнализируют о переполнении если результат не помещается в 64 битный результат. Функции реализованы в виде ассемблерной вставки, а вызываются через этот способ вызова функций по указателю. В архиве тест производительности данных функции и функции _allmul:
Сами функции:
- Код: Выделить всё
format PE GUI 4.0 DLL
entry EntryPoint
include 'win32wx.inc'
section '.code' code readable executable
proc EntryPoint hinstDLL,fdwReason,lpvReserved
mov eax,1
ret
endp
mul64:
mov eax, [esp + 0x10] ; bh
cmp dword [esp + 0x08], 0 ; ah
je .no_ah
test eax, eax
jnz .set_overflow
mov eax, [esp + 0x0c] ; bl
mul dword [esp + 0x08] ; bl * ah
jmp .continue
.no_ah:
test eax, eax
jnz .has_bh
mov eax, [esp + 0x04] ; al
mul dword [esp + 0x0c] ; bl
jmp .remove_overflow
.has_bh:
mul dword [esp + 0x04] ; bh * al
.continue:
test edx, edx
jnz .set_overflow
mov ecx, eax
mov eax, [esp + 0x04] ; al
mul dword [esp + 0x0c] ; bl
add edx, ecx
jc .set_overflow
.remove_overflow:
mov ecx, [esp + 0x14]
mov [ecx], dword 0
ret 0x14
.set_overflow:
mov ecx, [esp + 0x14]
mov [ecx], dword 1
ret 0x14
imul64:
push ebx
xor ebx, ebx
mov eax, [esp + 0x0c] ; ah
bt eax, 31
jnc .check_b
xor ecx, ecx
neg dword [esp + 0x08] ; - al
sbb ecx, [esp + 0x0c]
mov [esp + 0x0c], ecx
inc ebx
.check_b:
mov eax, [esp + 0x14] ; bh
bt eax, 31
jnc .mul_start
xor ecx, ecx
neg dword [esp + 0x10] ; - bl
sbb ecx, [esp + 0x14]
mov [esp + 0x14], ecx
inc ebx
mov eax, ecx
.mul_start:
cmp dword [esp + 0x0c], 0 ; ah
je .no_ah
test eax, eax
jnz .set_overflow
mov eax, [esp + 0x10] ; bl
mul dword [esp + 0x0c] ; bl * ah
jmp .continue
.no_ah:
test eax, eax
jnz .has_bh
mov eax, [esp + 0x08] ; al
mul dword [esp + 0x10] ; bl
jmp .check_negate
.has_bh:
mul dword [esp + 0x08] ; bh * al
.continue:
jc .set_overflow
mov ecx, eax
mov eax, [esp + 0x08] ; al
mul dword [esp + 0x10] ; bl
add edx, ecx
jc .set_overflow
.check_negate:
jns .process_negate
test eax, eax
jnz .set_overflow
cmp edx, 0x80000000
jnz .set_overflow
test bl, 1
jnz .negate_result
jmp .set_overflow
.process_negate:
test bl, 1
jz .remove_overflow
.negate_result:
xor ecx, ecx
xchg ecx, edx
neg eax
sbb edx, ecx
.remove_overflow:
mov ecx, [esp + 0x18]
mov [ecx], dword 0
pop ebx
ret 0x14
.set_overflow:
mov ecx, [esp + 0x18]
mov [ecx], dword 1
pop ebx
ret 0x14
section '.edata' export data readable
export 'mul64.dll', mul64, 'mul64', \
imul64, 'imul64'
section '.reloc' fixups data discardable
if $=$$
dd 0,8
end if