Умножение 64 битных целых с индикацией переполнения.

Здесь можно найти готовые «кирпичики» — части кода, пригодные для построения более крупных проектов, а также решения различных типовых и не очень задач на VB.

Модератор: Brickgroup

The trick
Постоялец
Постоялец
 
Сообщения: 781
Зарегистрирован: 26.06.2010 (Сб) 23:08

Умножение 64 битных целых с индикацией переполнения.

Сообщение The trick » 04.02.2023 (Сб) 15:53

Обычно когда мне нужно работать с 64 битными целыми числами я использую тип Currency. Для сложений и вычитаний можно использовать обычные + и -. Для умножения и деления можно использовать _allmul, _alldiv:

Код: Выделить всё
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:

preview2.png
preview2.png (6.34 Кб) Просмотров: 177


Сами функции:

Код: Выделить всё
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
Вложения
mul64VB.zip
(3.23 Кб) Скачиваний: 26
UA6527P

Вернуться в Кирпичный завод

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 8

    TopList