1
0

arithutil.cpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360
  1. //------------------------------------------------------------------------------
  2. // File: ArithUtil.cpp
  3. //
  4. // Desc: DirectShow base classes - implements helper classes for building
  5. // multimedia filters.
  6. //
  7. // Copyright (c) 1992-2004 Microsoft Corporation. All rights reserved.
  8. //------------------------------------------------------------------------------
  9. #include <streams.h>
  10. //
  11. // Declare function from largeint.h we need so that PPC can build
  12. //
  13. //
  14. // Enlarged integer divide - 64-bits / 32-bits > 32-bits
  15. //
  16. #ifndef _X86_
  17. #define LLtoU64(x) (*(unsigned __int64*)(void*)(&(x)))
  18. __inline
  19. ULONG
  20. WINAPI
  21. EnlargedUnsignedDivide (
  22. IN ULARGE_INTEGER Dividend,
  23. IN ULONG Divisor,
  24. IN PULONG Remainder
  25. )
  26. {
  27. // return remainder if necessary
  28. if (Remainder != NULL)
  29. *Remainder = (ULONG)(LLtoU64(Dividend) % Divisor);
  30. return (ULONG)(LLtoU64(Dividend) / Divisor);
  31. }
  32. #else
  33. __inline
  34. ULONG
  35. WINAPI
  36. EnlargedUnsignedDivide (
  37. IN ULARGE_INTEGER Dividend,
  38. IN ULONG Divisor,
  39. IN PULONG Remainder
  40. )
  41. {
  42. ULONG ulResult;
  43. _asm {
  44. mov eax,Dividend.LowPart
  45. mov edx,Dividend.HighPart
  46. mov ecx,Remainder
  47. div Divisor
  48. or ecx,ecx
  49. jz short label
  50. mov [ecx],edx
  51. label:
  52. mov ulResult,eax
  53. }
  54. return ulResult;
  55. }
  56. #endif
  57. /* Arithmetic functions to help with time format conversions
  58. */
  59. #ifdef _M_ALPHA
  60. // work around bug in version 12.00.8385 of the alpha compiler where
  61. // UInt32x32To64 sign-extends its arguments (?)
  62. #undef UInt32x32To64
  63. #define UInt32x32To64(a, b) (((ULONGLONG)((ULONG)(a)) & 0xffffffff) * ((ULONGLONG)((ULONG)(b)) & 0xffffffff))
  64. #endif
  65. /* Compute (a * b + d) / c */
  66. LONGLONG WINAPI llMulDiv(LONGLONG a, LONGLONG b, LONGLONG c, LONGLONG d)
  67. {
  68. /* Compute the absolute values to avoid signed arithmetic problems */
  69. ULARGE_INTEGER ua, ub;
  70. DWORDLONG uc;
  71. ua.QuadPart = (DWORDLONG)(a >= 0 ? a : -a);
  72. ub.QuadPart = (DWORDLONG)(b >= 0 ? b : -b);
  73. uc = (DWORDLONG)(c >= 0 ? c : -c);
  74. BOOL bSign = (a < 0) ^ (b < 0);
  75. /* Do long multiplication */
  76. ULARGE_INTEGER p[2];
  77. p[0].QuadPart = UInt32x32To64(ua.LowPart, ub.LowPart);
  78. /* This next computation cannot overflow into p[1].HighPart because
  79. the max number we can compute here is:
  80. (2 ** 32 - 1) * (2 ** 32 - 1) + // ua.LowPart * ub.LowPart
  81. (2 ** 32) * (2 ** 31) * (2 ** 32 - 1) * 2 // x.LowPart * y.HighPart * 2
  82. == 2 ** 96 - 2 ** 64 + (2 ** 64 - 2 ** 33 + 1)
  83. == 2 ** 96 - 2 ** 33 + 1
  84. < 2 ** 96
  85. */
  86. ULARGE_INTEGER x;
  87. x.QuadPart = UInt32x32To64(ua.LowPart, ub.HighPart) +
  88. UInt32x32To64(ua.HighPart, ub.LowPart) +
  89. p[0].HighPart;
  90. p[0].HighPart = x.LowPart;
  91. p[1].QuadPart = UInt32x32To64(ua.HighPart, ub.HighPart) + x.HighPart;
  92. if (d != 0) {
  93. ULARGE_INTEGER ud[2];
  94. if (bSign) {
  95. ud[0].QuadPart = (DWORDLONG)(-d);
  96. if (d > 0) {
  97. /* -d < 0 */
  98. ud[1].QuadPart = (DWORDLONG)(LONGLONG)-1;
  99. } else {
  100. ud[1].QuadPart = (DWORDLONG)0;
  101. }
  102. } else {
  103. ud[0].QuadPart = (DWORDLONG)d;
  104. if (d < 0) {
  105. ud[1].QuadPart = (DWORDLONG)(LONGLONG)-1;
  106. } else {
  107. ud[1].QuadPart = (DWORDLONG)0;
  108. }
  109. }
  110. /* Now do extended addition */
  111. ULARGE_INTEGER uliTotal;
  112. /* Add ls DWORDs */
  113. uliTotal.QuadPart = (DWORDLONG)ud[0].LowPart + p[0].LowPart;
  114. p[0].LowPart = uliTotal.LowPart;
  115. /* Propagate carry */
  116. uliTotal.LowPart = uliTotal.HighPart;
  117. uliTotal.HighPart = 0;
  118. /* Add 2nd most ls DWORDs */
  119. uliTotal.QuadPart += (DWORDLONG)ud[0].HighPart + p[0].HighPart;
  120. p[0].HighPart = uliTotal.LowPart;
  121. /* Propagate carry */
  122. uliTotal.LowPart = uliTotal.HighPart;
  123. uliTotal.HighPart = 0;
  124. /* Add MS DWORDLONGs - no carry expected */
  125. p[1].QuadPart += ud[1].QuadPart + uliTotal.QuadPart;
  126. /* Now see if we got a sign change from the addition */
  127. if ((LONG)p[1].HighPart < 0) {
  128. bSign = !bSign;
  129. /* Negate the current value (ugh!) */
  130. p[0].QuadPart = ~p[0].QuadPart;
  131. p[1].QuadPart = ~p[1].QuadPart;
  132. p[0].QuadPart += 1;
  133. p[1].QuadPart += (p[0].QuadPart == 0);
  134. }
  135. }
  136. /* Now for the division */
  137. if (c < 0) {
  138. bSign = !bSign;
  139. }
  140. /* This will catch c == 0 and overflow */
  141. if (uc <= p[1].QuadPart) {
  142. return bSign ? (LONGLONG)0x8000000000000000 :
  143. (LONGLONG)0x7FFFFFFFFFFFFFFF;
  144. }
  145. DWORDLONG ullResult;
  146. /* Do the division */
  147. /* If the dividend is a DWORD_LONG use the compiler */
  148. if (p[1].QuadPart == 0) {
  149. ullResult = p[0].QuadPart / uc;
  150. return bSign ? -(LONGLONG)ullResult : (LONGLONG)ullResult;
  151. }
  152. /* If the divisor is a DWORD then its simpler */
  153. ULARGE_INTEGER ulic;
  154. ulic.QuadPart = uc;
  155. if (ulic.HighPart == 0) {
  156. ULARGE_INTEGER uliDividend;
  157. ULARGE_INTEGER uliResult;
  158. DWORD dwDivisor = (DWORD)uc;
  159. // ASSERT(p[1].HighPart == 0 && p[1].LowPart < dwDivisor);
  160. uliDividend.HighPart = p[1].LowPart;
  161. uliDividend.LowPart = p[0].HighPart;
  162. #ifndef USE_LARGEINT
  163. uliResult.HighPart = (DWORD)(uliDividend.QuadPart / dwDivisor);
  164. p[0].HighPart = (DWORD)(uliDividend.QuadPart % dwDivisor);
  165. uliResult.LowPart = 0;
  166. uliResult.QuadPart = p[0].QuadPart / dwDivisor + uliResult.QuadPart;
  167. #else
  168. /* NOTE - this routine will take exceptions if
  169. the result does not fit in a DWORD
  170. */
  171. if (uliDividend.QuadPart >= (DWORDLONG)dwDivisor) {
  172. uliResult.HighPart = EnlargedUnsignedDivide(
  173. uliDividend,
  174. dwDivisor,
  175. &p[0].HighPart);
  176. } else {
  177. uliResult.HighPart = 0;
  178. }
  179. uliResult.LowPart = EnlargedUnsignedDivide(
  180. p[0],
  181. dwDivisor,
  182. NULL);
  183. #endif
  184. return bSign ? -(LONGLONG)uliResult.QuadPart :
  185. (LONGLONG)uliResult.QuadPart;
  186. }
  187. ullResult = 0;
  188. /* OK - do long division */
  189. for (int i = 0; i < 64; i++) {
  190. ullResult <<= 1;
  191. /* Shift 128 bit p left 1 */
  192. p[1].QuadPart <<= 1;
  193. if ((p[0].HighPart & 0x80000000) != 0) {
  194. p[1].LowPart++;
  195. }
  196. p[0].QuadPart <<= 1;
  197. /* Compare */
  198. if (uc <= p[1].QuadPart) {
  199. p[1].QuadPart -= uc;
  200. ullResult += 1;
  201. }
  202. }
  203. return bSign ? - (LONGLONG)ullResult : (LONGLONG)ullResult;
  204. }
  205. LONGLONG WINAPI Int64x32Div32(LONGLONG a, LONG b, LONG c, LONG d)
  206. {
  207. ULARGE_INTEGER ua;
  208. DWORD ub;
  209. DWORD uc;
  210. /* Compute the absolute values to avoid signed arithmetic problems */
  211. ua.QuadPart = (DWORDLONG)(a >= 0 ? a : -a);
  212. ub = (DWORD)(b >= 0 ? b : -b);
  213. uc = (DWORD)(c >= 0 ? c : -c);
  214. BOOL bSign = (a < 0) ^ (b < 0);
  215. /* Do long multiplication */
  216. ULARGE_INTEGER p0;
  217. DWORD p1;
  218. p0.QuadPart = UInt32x32To64(ua.LowPart, ub);
  219. if (ua.HighPart != 0) {
  220. ULARGE_INTEGER x;
  221. x.QuadPart = UInt32x32To64(ua.HighPart, ub) + p0.HighPart;
  222. p0.HighPart = x.LowPart;
  223. p1 = x.HighPart;
  224. } else {
  225. p1 = 0;
  226. }
  227. if (d != 0) {
  228. ULARGE_INTEGER ud0;
  229. DWORD ud1;
  230. if (bSign) {
  231. //
  232. // Cast d to LONGLONG first otherwise -0x80000000 sign extends
  233. // incorrectly
  234. //
  235. ud0.QuadPart = (DWORDLONG)(-(LONGLONG)d);
  236. if (d > 0) {
  237. /* -d < 0 */
  238. ud1 = (DWORD)-1;
  239. } else {
  240. ud1 = (DWORD)0;
  241. }
  242. } else {
  243. ud0.QuadPart = (DWORDLONG)d;
  244. if (d < 0) {
  245. ud1 = (DWORD)-1;
  246. } else {
  247. ud1 = (DWORD)0;
  248. }
  249. }
  250. /* Now do extended addition */
  251. ULARGE_INTEGER uliTotal;
  252. /* Add ls DWORDs */
  253. uliTotal.QuadPart = (DWORDLONG)ud0.LowPart + p0.LowPart;
  254. p0.LowPart = uliTotal.LowPart;
  255. /* Propagate carry */
  256. uliTotal.LowPart = uliTotal.HighPart;
  257. uliTotal.HighPart = 0;
  258. /* Add 2nd most ls DWORDs */
  259. uliTotal.QuadPart += (DWORDLONG)ud0.HighPart + p0.HighPart;
  260. p0.HighPart = uliTotal.LowPart;
  261. /* Add MS DWORDLONGs - no carry expected */
  262. p1 += ud1 + uliTotal.HighPart;
  263. /* Now see if we got a sign change from the addition */
  264. if ((LONG)p1 < 0) {
  265. bSign = !bSign;
  266. /* Negate the current value (ugh!) */
  267. p0.QuadPart = ~p0.QuadPart;
  268. p1 = ~p1;
  269. p0.QuadPart += 1;
  270. p1 += (p0.QuadPart == 0);
  271. }
  272. }
  273. /* Now for the division */
  274. if (c < 0) {
  275. bSign = !bSign;
  276. }
  277. /* This will catch c == 0 and overflow */
  278. if (uc <= p1) {
  279. return bSign ? (LONGLONG)0x8000000000000000 :
  280. (LONGLONG)0x7FFFFFFFFFFFFFFF;
  281. }
  282. /* Do the division */
  283. /* If the divisor is a DWORD then its simpler */
  284. ULARGE_INTEGER uliDividend;
  285. ULARGE_INTEGER uliResult;
  286. DWORD dwDivisor = uc;
  287. uliDividend.HighPart = p1;
  288. uliDividend.LowPart = p0.HighPart;
  289. /* NOTE - this routine will take exceptions if
  290. the result does not fit in a DWORD
  291. */
  292. if (uliDividend.QuadPart >= (DWORDLONG)dwDivisor) {
  293. uliResult.HighPart = EnlargedUnsignedDivide(
  294. uliDividend,
  295. dwDivisor,
  296. &p0.HighPart);
  297. } else {
  298. uliResult.HighPart = 0;
  299. }
  300. uliResult.LowPart = EnlargedUnsignedDivide(
  301. p0,
  302. dwDivisor,
  303. NULL);
  304. return bSign ? -(LONGLONG)uliResult.QuadPart :
  305. (LONGLONG)uliResult.QuadPart;
  306. }