Page 1 of 1

MulDiv

Posted: Wed Aug 28, 2013 3:30 pm
by wilbert
I tried to mimic the MulDiv procedure windows offers since it's not available on OS X.
The only difference is that I used a different error code instead of -1 since -1 can also be a valid result.

Code: Select all

#MULDIV_ERROR = -2147483648

Procedure MulDiv(Number.l, Numerator.l, Denominator.l)
  !mov eax, [p.v_Number]
  !mov edx, [p.v_Numerator]
  !mov ecx, [p.v_Denominator]
  CompilerIf #PB_Compiler_Processor = #PB_Processor_x64
    !push rbx  
  CompilerElse
    !push ebx
  CompilerEndIf 
  
  ; check denominator
  !xor ebx, ebx
  !test ecx, ecx
  !jz mul_div_error; division by zero
  !jns mul_div_cont1; positive denominator ?
  ; no, make denominator positive
  !not ebx
  !neg ecx
  !mul_div_cont1:
  
  ; multiply Number and Numerator
  !imul edx
  !test edx, edx
  !jns mul_div_cont2; positive multiply result ?
  ; no, make multiply result positive
  !not ebx
  !neg edx
  !neg eax
  !sbb edx, 0
  !mul_div_cont2:
  
  ; divide and round
  !cmp ecx, edx
  !jbe mul_div_error; overflow
  !div ecx
  !shl edx, 1
  !sub edx, ecx
  !cmc
  !adc eax, 0
  !js mul_div_error; overflow
  
  ; restore sign to negative if required
  !neg ebx
  !jz mul_div_cont3
  CompilerIf #PB_Compiler_Processor = #PB_Processor_x64
    !neg rax
    !mul_div_cont3:
    !pop rbx
  CompilerElse
    !neg eax
    !mul_div_cont3:
    !pop ebx
  CompilerEndIf  
  ProcedureReturn
  
  !mul_div_error:
  CompilerIf #PB_Compiler_Processor = #PB_Processor_x64
    !pop rbx
  CompilerElse
    !pop ebx
  CompilerEndIf  
  ProcedureReturn #MULDIV_ERROR
EndProcedure
Example :
Debug MulDiv(3, 40, 80)

3 * 40 / 80 ==> 2 (1.5 rounded to integer)