//------------------------------------------------------------------------------ | |
// File: ArithUtil.cpp | |
// | |
// Desc: DirectShow base classes - implements helper classes for building | |
// multimedia filters. | |
// | |
// Copyright (c) 1992-2004 Microsoft Corporation. All rights reserved. | |
//------------------------------------------------------------------------------ | |
#include <streams.h> | |
// | |
// Declare function from largeint.h we need so that PPC can build | |
// | |
// | |
// Enlarged integer divide - 64-bits / 32-bits > 32-bits | |
// | |
#ifndef _X86_ | |
#define LLtoU64(x) (*(unsigned __int64*)(void*)(&(x))) | |
__inline | |
ULONG | |
WINAPI | |
EnlargedUnsignedDivide ( | |
IN ULARGE_INTEGER Dividend, | |
IN ULONG Divisor, | |
IN PULONG Remainder | |
) | |
{ | |
// return remainder if necessary | |
if (Remainder != NULL) | |
*Remainder = (ULONG)(LLtoU64(Dividend) % Divisor); | |
return (ULONG)(LLtoU64(Dividend) / Divisor); | |
} | |
#else | |
__inline | |
ULONG | |
WINAPI | |
EnlargedUnsignedDivide ( | |
IN ULARGE_INTEGER Dividend, | |
IN ULONG Divisor, | |
IN PULONG Remainder | |
) | |
{ | |
ULONG ulResult; | |
_asm { | |
mov eax,Dividend.LowPart | |
mov edx,Dividend.HighPart | |
mov ecx,Remainder | |
div Divisor | |
or ecx,ecx | |
jz short label | |
mov [ecx],edx | |
label: | |
mov ulResult,eax | |
} | |
return ulResult; | |
} | |
#endif | |
/* Arithmetic functions to help with time format conversions | |
*/ | |
#ifdef _M_ALPHA | |
// work around bug in version 12.00.8385 of the alpha compiler where | |
// UInt32x32To64 sign-extends its arguments (?) | |
#undef UInt32x32To64 | |
#define UInt32x32To64(a, b) (((ULONGLONG)((ULONG)(a)) & 0xffffffff) * ((ULONGLONG)((ULONG)(b)) & 0xffffffff)) | |
#endif | |
/* Compute (a * b + d) / c */ | |
LONGLONG WINAPI llMulDiv(LONGLONG a, LONGLONG b, LONGLONG c, LONGLONG d) | |
{ | |
/* Compute the absolute values to avoid signed arithmetic problems */ | |
ULARGE_INTEGER ua, ub; | |
DWORDLONG uc; | |
ua.QuadPart = (DWORDLONG)(a >= 0 ? a : -a); | |
ub.QuadPart = (DWORDLONG)(b >= 0 ? b : -b); | |
uc = (DWORDLONG)(c >= 0 ? c : -c); | |
BOOL bSign = (a < 0) ^ (b < 0); | |
/* Do long multiplication */ | |
ULARGE_INTEGER p[2]; | |
p[0].QuadPart = UInt32x32To64(ua.LowPart, ub.LowPart); | |
/* This next computation cannot overflow into p[1].HighPart because | |
the max number we can compute here is: | |
(2 ** 32 - 1) * (2 ** 32 - 1) + // ua.LowPart * ub.LowPart | |
(2 ** 32) * (2 ** 31) * (2 ** 32 - 1) * 2 // x.LowPart * y.HighPart * 2 | |
== 2 ** 96 - 2 ** 64 + (2 ** 64 - 2 ** 33 + 1) | |
== 2 ** 96 - 2 ** 33 + 1 | |
< 2 ** 96 | |
*/ | |
ULARGE_INTEGER x; | |
x.QuadPart = UInt32x32To64(ua.LowPart, ub.HighPart) + | |
UInt32x32To64(ua.HighPart, ub.LowPart) + | |
p[0].HighPart; | |
p[0].HighPart = x.LowPart; | |
p[1].QuadPart = UInt32x32To64(ua.HighPart, ub.HighPart) + x.HighPart; | |
if (d != 0) { | |
ULARGE_INTEGER ud[2]; | |
if (bSign) { | |
ud[0].QuadPart = (DWORDLONG)(-d); | |
if (d > 0) { | |
/* -d < 0 */ | |
ud[1].QuadPart = (DWORDLONG)(LONGLONG)-1; | |
} else { | |
ud[1].QuadPart = (DWORDLONG)0; | |
} | |
} else { | |
ud[0].QuadPart = (DWORDLONG)d; | |
if (d < 0) { | |
ud[1].QuadPart = (DWORDLONG)(LONGLONG)-1; | |
} else { | |
ud[1].QuadPart = (DWORDLONG)0; | |
} | |
} | |
/* Now do extended addition */ | |
ULARGE_INTEGER uliTotal; | |
/* Add ls DWORDs */ | |
uliTotal.QuadPart = (DWORDLONG)ud[0].LowPart + p[0].LowPart; | |
p[0].LowPart = uliTotal.LowPart; | |
/* Propagate carry */ | |
uliTotal.LowPart = uliTotal.HighPart; | |
uliTotal.HighPart = 0; | |
/* Add 2nd most ls DWORDs */ | |
uliTotal.QuadPart += (DWORDLONG)ud[0].HighPart + p[0].HighPart; | |
p[0].HighPart = uliTotal.LowPart; | |
/* Propagate carry */ | |
uliTotal.LowPart = uliTotal.HighPart; | |
uliTotal.HighPart = 0; | |
/* Add MS DWORDLONGs - no carry expected */ | |
p[1].QuadPart += ud[1].QuadPart + uliTotal.QuadPart; | |
/* Now see if we got a sign change from the addition */ | |
if ((LONG)p[1].HighPart < 0) { | |
bSign = !bSign; | |
/* Negate the current value (ugh!) */ | |
p[0].QuadPart = ~p[0].QuadPart; | |
p[1].QuadPart = ~p[1].QuadPart; | |
p[0].QuadPart += 1; | |
p[1].QuadPart += (p[0].QuadPart == 0); | |
} | |
} | |
/* Now for the division */ | |
if (c < 0) { | |
bSign = !bSign; | |
} | |
/* This will catch c == 0 and overflow */ | |
if (uc <= p[1].QuadPart) { | |
return bSign ? (LONGLONG)0x8000000000000000 : | |
(LONGLONG)0x7FFFFFFFFFFFFFFF; | |
} | |
DWORDLONG ullResult; | |
/* Do the division */ | |
/* If the dividend is a DWORD_LONG use the compiler */ | |
if (p[1].QuadPart == 0) { | |
ullResult = p[0].QuadPart / uc; | |
return bSign ? -(LONGLONG)ullResult : (LONGLONG)ullResult; | |
} | |
/* If the divisor is a DWORD then its simpler */ | |
ULARGE_INTEGER ulic; | |
ulic.QuadPart = uc; | |
if (ulic.HighPart == 0) { | |
ULARGE_INTEGER uliDividend; | |
ULARGE_INTEGER uliResult; | |
DWORD dwDivisor = (DWORD)uc; | |
// ASSERT(p[1].HighPart == 0 && p[1].LowPart < dwDivisor); | |
uliDividend.HighPart = p[1].LowPart; | |
uliDividend.LowPart = p[0].HighPart; | |
#ifndef USE_LARGEINT | |
uliResult.HighPart = (DWORD)(uliDividend.QuadPart / dwDivisor); | |
p[0].HighPart = (DWORD)(uliDividend.QuadPart % dwDivisor); | |
uliResult.LowPart = 0; | |
uliResult.QuadPart = p[0].QuadPart / dwDivisor + uliResult.QuadPart; | |
#else | |
/* NOTE - this routine will take exceptions if | |
the result does not fit in a DWORD | |
*/ | |
if (uliDividend.QuadPart >= (DWORDLONG)dwDivisor) { | |
uliResult.HighPart = EnlargedUnsignedDivide( | |
uliDividend, | |
dwDivisor, | |
&p[0].HighPart); | |
} else { | |
uliResult.HighPart = 0; | |
} | |
uliResult.LowPart = EnlargedUnsignedDivide( | |
p[0], | |
dwDivisor, | |
NULL); | |
#endif | |
return bSign ? -(LONGLONG)uliResult.QuadPart : | |
(LONGLONG)uliResult.QuadPart; | |
} | |
ullResult = 0; | |
/* OK - do long division */ | |
for (int i = 0; i < 64; i++) { | |
ullResult <<= 1; | |
/* Shift 128 bit p left 1 */ | |
p[1].QuadPart <<= 1; | |
if ((p[0].HighPart & 0x80000000) != 0) { | |
p[1].LowPart++; | |
} | |
p[0].QuadPart <<= 1; | |
/* Compare */ | |
if (uc <= p[1].QuadPart) { | |
p[1].QuadPart -= uc; | |
ullResult += 1; | |
} | |
} | |
return bSign ? - (LONGLONG)ullResult : (LONGLONG)ullResult; | |
} | |
LONGLONG WINAPI Int64x32Div32(LONGLONG a, LONG b, LONG c, LONG d) | |
{ | |
ULARGE_INTEGER ua; | |
DWORD ub; | |
DWORD uc; | |
/* Compute the absolute values to avoid signed arithmetic problems */ | |
ua.QuadPart = (DWORDLONG)(a >= 0 ? a : -a); | |
ub = (DWORD)(b >= 0 ? b : -b); | |
uc = (DWORD)(c >= 0 ? c : -c); | |
BOOL bSign = (a < 0) ^ (b < 0); | |
/* Do long multiplication */ | |
ULARGE_INTEGER p0; | |
DWORD p1; | |
p0.QuadPart = UInt32x32To64(ua.LowPart, ub); | |
if (ua.HighPart != 0) { | |
ULARGE_INTEGER x; | |
x.QuadPart = UInt32x32To64(ua.HighPart, ub) + p0.HighPart; | |
p0.HighPart = x.LowPart; | |
p1 = x.HighPart; | |
} else { | |
p1 = 0; | |
} | |
if (d != 0) { | |
ULARGE_INTEGER ud0; | |
DWORD ud1; | |
if (bSign) { | |
// | |
// Cast d to LONGLONG first otherwise -0x80000000 sign extends | |
// incorrectly | |
// | |
ud0.QuadPart = (DWORDLONG)(-(LONGLONG)d); | |
if (d > 0) { | |
/* -d < 0 */ | |
ud1 = (DWORD)-1; | |
} else { | |
ud1 = (DWORD)0; | |
} | |
} else { | |
ud0.QuadPart = (DWORDLONG)d; | |
if (d < 0) { | |
ud1 = (DWORD)-1; | |
} else { | |
ud1 = (DWORD)0; | |
} | |
} | |
/* Now do extended addition */ | |
ULARGE_INTEGER uliTotal; | |
/* Add ls DWORDs */ | |
uliTotal.QuadPart = (DWORDLONG)ud0.LowPart + p0.LowPart; | |
p0.LowPart = uliTotal.LowPart; | |
/* Propagate carry */ | |
uliTotal.LowPart = uliTotal.HighPart; | |
uliTotal.HighPart = 0; | |
/* Add 2nd most ls DWORDs */ | |
uliTotal.QuadPart += (DWORDLONG)ud0.HighPart + p0.HighPart; | |
p0.HighPart = uliTotal.LowPart; | |
/* Add MS DWORDLONGs - no carry expected */ | |
p1 += ud1 + uliTotal.HighPart; | |
/* Now see if we got a sign change from the addition */ | |
if ((LONG)p1 < 0) { | |
bSign = !bSign; | |
/* Negate the current value (ugh!) */ | |
p0.QuadPart = ~p0.QuadPart; | |
p1 = ~p1; | |
p0.QuadPart += 1; | |
p1 += (p0.QuadPart == 0); | |
} | |
} | |
/* Now for the division */ | |
if (c < 0) { | |
bSign = !bSign; | |
} | |
/* This will catch c == 0 and overflow */ | |
if (uc <= p1) { | |
return bSign ? (LONGLONG)0x8000000000000000 : | |
(LONGLONG)0x7FFFFFFFFFFFFFFF; | |
} | |
/* Do the division */ | |
/* If the divisor is a DWORD then its simpler */ | |
ULARGE_INTEGER uliDividend; | |
ULARGE_INTEGER uliResult; | |
DWORD dwDivisor = uc; | |
uliDividend.HighPart = p1; | |
uliDividend.LowPart = p0.HighPart; | |
/* NOTE - this routine will take exceptions if | |
the result does not fit in a DWORD | |
*/ | |
if (uliDividend.QuadPart >= (DWORDLONG)dwDivisor) { | |
uliResult.HighPart = EnlargedUnsignedDivide( | |
uliDividend, | |
dwDivisor, | |
&p0.HighPart); | |
} else { | |
uliResult.HighPart = 0; | |
} | |
uliResult.LowPart = EnlargedUnsignedDivide( | |
p0, | |
dwDivisor, | |
NULL); | |
return bSign ? -(LONGLONG)uliResult.QuadPart : | |
(LONGLONG)uliResult.QuadPart; | |
} |