#include #include "lsidefs.h" #include "zqfromza.h" #ifdef _X86_ /* =========================================================== */ /* */ /* Functions implemented on Intel X86 Assember */ /* */ /* =========================================================== */ #define HIWORD(x) DWORD PTR [x+4] #define LOWORD(x) DWORD PTR [x] long ZqFromZa_Asm (long dzqInch, long za) { long result; __asm { mov eax, za; cmp eax, 0 jge POSITIVE neg eax mul dzqInch; add eax, czaUnitInch / 2 mov ecx, czaUnitInch adc edx, 0 div ecx; neg eax jmp RETURN POSITIVE: mul dzqInch; add eax, czaUnitInch / 2 mov ecx, czaUnitInch adc edx, 0 div ecx; RETURN: mov result, eax }; /* Assert (result == ZqFromZa_C (dzqInch, za)); */ return result; } /* D I V 6 4 _ A S M */ /*---------------------------------------------------------------------------- %%Function: Div64_Asm %%Contact: antons Intel assembler implementation of 64-bit division. The orignal code was taken from lldiv.asm (VC++ 6.0). ----------------------------------------------------------------------------*/ __int64 Div64_Asm (__int64 DVND, __int64 DVSR) { __int64 result; __asm { xor edi,edi // result sign assumed positive mov eax,HIWORD(DVND) // hi word of a or eax,eax // test to see if signed jge L1 // skip rest if a is already positive inc edi // complement result sign flag mov edx,LOWORD(DVND) // lo word of a neg eax // make a positive neg edx sbb eax,0 mov HIWORD(DVND),eax // save positive value mov LOWORD(DVND),edx L1: mov eax,HIWORD(DVSR) // hi word of b or eax,eax // test to see if signed jge L2 // skip rest if b is already positive inc edi // complement the result sign flag mov edx,LOWORD(DVSR) // lo word of a neg eax // make b positive neg edx sbb eax,0 mov HIWORD(DVSR),eax // save positive value mov LOWORD(DVSR),edx L2: // Now do the divide. First look to see if the divisor is less than 4194304K. // If so, then we can use a simple algorithm with word divides, otherwise // things get a little more complex. // // NOTE - eax currently contains the high order word of DVSR or eax,eax // check to see if divisor < 4194304K jnz L3 // nope, gotta do this the hard way mov ecx,LOWORD(DVSR) // load divisor mov eax,HIWORD(DVND) // load high word of dividend xor edx,edx div ecx // eax <- high order bits of quotient mov ebx,eax // save high bits of quotient mov eax,LOWORD(DVND) // edx:eax <- remainder:lo word of dividend div ecx // eax <- low order bits of quotient mov edx,ebx // edx:eax <- quotient jmp L4 // set sign, restore stack and return // // Here we do it the hard way. Remember, eax contains the high word of DVSR // L3: mov ebx,eax // ebx:ecx <- divisor mov ecx,LOWORD(DVSR) mov edx,HIWORD(DVND) // edx:eax <- dividend mov eax,LOWORD(DVND) L5: shr ebx,1 // shift divisor right one bit rcr ecx,1 shr edx,1 // shift dividend right one bit rcr eax,1 or ebx,ebx jnz L5 // loop until divisor < 4194304K div ecx // now divide, ignore remainder mov esi,eax // save quotient /* // We may be off by one, so to check, we will multiply the quotient // by the divisor and check the result against the orignal dividend // Note that we must also check for overflow, which can occur if the // dividend is close to 2**64 and the quotient is off by 1. */ mul HIWORD(DVSR) // QUOT * HIWORD(DVSR) mov ecx,eax mov eax,LOWORD(DVSR) mul esi // QUOT * LOWORD(DVSR) add edx,ecx // EDX:EAX = QUOT * DVSR jc L6 // carry means Quotient is off by 1 // // do long compare here between original dividend and the result of the // multiply in edx:eax. If original is larger or equal, we are ok, otherwise // subtract one (1) from the quotient. // cmp edx,HIWORD(DVND) // compare hi words of result and original ja L6 // if result > original, do subtract jb L7 // if result < original, we are ok cmp eax,LOWORD(DVND) // hi words are equal, compare lo words jbe L7 // if less or equal we are ok, else subtract L6: dec esi // subtract 1 from quotient L7: xor edx,edx // edx:eax <- quotient mov eax,esi // // Just the cleanup left to do. edx:eax contains the quotient. Set the sign // according to the save value, cleanup the stack, and return. // L4: dec edi // check to see if result is negative jnz L8 // if EDI == 0, result should be negative neg edx // otherwise, negate the result neg eax sbb edx,0 // // Restore the saved registers and return. // L8: mov HIWORD(result),edx mov LOWORD(result),eax }; /* ASM */ return result; } /* M U L 6 4 _ A S M */ /*---------------------------------------------------------------------------- %%Function: Mul64_Asm %%Contact: antons Intel assembler implementation of 64-bit multiplication. The orignal code was taken from llmul.asm (VC++ 6.0). ----------------------------------------------------------------------------*/ __int64 Mul64_Asm (__int64 A, __int64 B) { __int64 result; __asm { mov eax,HIWORD(A) mov ecx,LOWORD(B) mul ecx // eax has AHI, ecx has BLO, so AHI * BLO mov esi,eax // save result mov eax,LOWORD(A) mul HIWORD(B) // ALO * BHI add esi,eax // ebx = ((ALO * BHI) + (AHI * BLO)) mov eax,LOWORD(A) // ecx = BLO mul ecx // so edx:eax = ALO*BLO add edx,esi // now edx has all the LO*HI stuff mov HIWORD(result),edx mov LOWORD(result),eax }; /* ASM */ return result; } /* =========================================================== */ /* */ /* End of Assembler functions */ /* */ /* =========================================================== */ #endif /* _X86_ */ long ZqFromZa_C (long dzqInch, long za) { long cInches; long zaExtra; if (za < 0) { Assert (((long) -za) > 0); /* Check for overflow */ return -ZqFromZa_C (dzqInch, -za); }; Assert(0 <= za); Assert(0 < dzqInch && dzqInch < zqLim); Assert(0 < czaUnitInch); cInches = za / czaUnitInch; zaExtra = za % czaUnitInch; return (cInches * dzqInch) + ((zaExtra * dzqInch) + (czaUnitInch/2)) / czaUnitInch; } long ZaFromZq(long dzqInch, long zq) { long cInches; long zqExtra; if (zq < 0) return -ZaFromZq(dzqInch, -zq); Assert(0 <= zq); Assert(0 < dzqInch && dzqInch < zqLim); Assert(0 < czaUnitInch); cInches = zq / dzqInch; zqExtra = zq % dzqInch; return (cInches * czaUnitInch) + ((zqExtra * czaUnitInch) + ((unsigned long) dzqInch/2)) / dzqInch; } long LsLwMultDivR(long l, long lNumer, long lDenom) { __int64 llT; Assert(lDenom != 0); if (lDenom == 0) /* this is really sloppy! Don't depend on this! */ return LONG_MAX; if (l == 0) return 0; if (lNumer == lDenom) return l; llT = Mul64 (l, lNumer); if ( (l ^ lNumer ^ lDenom) < 0) /* xor sign bits to give result sign */ llT -= lDenom / 2; else llT += lDenom / 2; if ((__int64)(long)llT == llT) /* Did the multiply fit in 32-bits */ return ( ((long)llT) / lDenom); /* If so, do a 32-bit divide. */ llT = Div64 (llT, lDenom); if (llT > LONG_MAX) return LONG_MAX; else if (llT < LONG_MIN) return LONG_MIN; else return (long) llT; }