Changeset 543
- Timestamp:
- 01/15/08 03:12:46 (11 months ago)
- Files:
-
- candidate/phobos/std/math.d (modified) (26 diffs)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
candidate/phobos/std/math.d
r510 r543 67 67 private import std.c.math; 68 68 private import std.traits; 69 70 /* Most of the functions depend on the format of the largest IEEE floating-point type. 71 * These code will differ depending on whether 'real' is 64, 80, or 128 bits, 72 * and whether it is a big-endian or little-endian architecture. 73 * Only three 'real' ABIs are currently supported: 74 * 64 bit Big-endian (eg PowerPC) 75 * 64 bit Little-endian 76 * 80 bit Little-endian, with implied bit (eg x87, Itanium). 77 */ 78 version(LittleEndian) { 79 static assert(real.mant_dig == 53 || real.mant_dig==64, 80 "Only 64-bit and 80-bit reals are supported for LittleEndian CPUs"); 81 } else { 82 static assert(real.mant_dig == 53, 83 "Only 64-bit reals are supported for BigEndian CPUs."); 84 } 85 69 86 70 87 class NotImplemented : Error … … 145 162 unittest 146 163 { 147 assert(is PosZero(abs(-0.0L)));164 assert(isIdentical(abs(-0.0L), 0.0L)); 148 165 assert(isnan(abs(real.nan))); 149 166 assert(abs(-real.infinity) == real.infinity); … … 470 487 unittest 471 488 { 472 assert(is PosZero(asinh(0.0)));473 assert(is NegZero(asinh(-0.0)));489 assert(isIdentical(asinh(0.0), 0.0)); 490 assert(isIdentical(asinh(-0.0), -0.0)); 474 491 assert(asinh(real.infinity) == real.infinity); 475 492 assert(asinh(-real.infinity) == -real.infinity); … … 502 519 unittest 503 520 { 504 assert(is PosZero(atanh(0.0)));505 assert(is NegZero(atanh(-0.0)));521 assert(isIdentical(atanh(0.0), 0.0)); 522 assert(isIdentical(atanh(-0.0),-0.0)); 506 523 assert(isnan(atanh(real.nan))); 507 524 assert(isnan(atanh(-real.infinity))); … … 619 636 real expm1(real x) { return std.c.math.expm1l(x); } 620 637 638 /** 639 * Calculate cos(y) + i sin(y). 640 * 641 * On many CPUs (such as x86), this is a very efficient operation; 642 * almost twice as fast as calculating sin(y) and cos(y) 643 * seperately, and is the preferred method when both are required. 644 */ 645 creal expi(real y) 646 { 647 version(D_InlineAsm_X86) 648 { 649 asm 650 { 651 fld y; 652 fsincos; 653 fxch st(1), st(0); 654 } 655 } 656 else 657 { 658 return cos(y) + sin(y)*1i; 659 } 660 } 661 662 unittest 663 { 664 assert(expi(1.3e5L) == cos(1.3e5L) + sin(1.3e5L) * 1i); 665 assert(expi(0.0L) == 1L + 0.0Li); 666 } 621 667 622 668 /********************************************************************* … … 638 684 */ 639 685 640 641 686 real frexp(real value, out int exp) 642 687 { … … 645 690 uint ex; 646 691 647 // If exponent is non-zero 648 ex = vu[4] & 0x7FFF; 649 if (ex) 650 { 651 if (ex == 0x7FFF) 652 { // infinity or NaN 653 if (*vl & 0x7FFFFFFFFFFFFFFF) // if NaN 654 { *vl |= 0xC000000000000000; // convert $(NAN)S to $(NAN)Q 692 static if (real.mant_dig==64) const ushort EXPMASK = 0x7FFF; 693 else const ushort EXPMASK = 0x7FF0; 694 695 version(LittleEndian) { 696 static if (real.mant_dig==64) const int EXPONENTPOS = 4; 697 else const int EXPONENTPOS = 3; 698 } else { // BigEndian 699 const int EXPONENTPOS = 0; 700 } 701 702 ex = vu[EXPONENTPOS] & EXPMASK; 703 static if (real.mant_dig == 64) { 704 // 80-bit reals 705 if (ex) { // If exponent is non-zero 706 if (ex == EXPMASK) { // infinity or NaN 707 // 80-bit reals 708 if (*vl & 0x7FFFFFFFFFFFFFFF) { // NaN 709 *vl |= 0xC000000000000000; // convert $(NAN)S to $(NAN)Q 655 710 exp = int.min; 656 } 657 else if (vu[4] & 0x8000) 658 { // negative infinity 711 } else if (vu[EXPONENTPOS] & 0x8000) { // negative infinity 659 712 exp = int.min; 660 } 661 else 662 { // positive infinity 713 } else { // positive infinity 663 714 exp = int.max; 664 715 } 665 } 666 else 667 { 716 } else { 668 717 exp = ex - 0x3FFE; 669 vu[4] = cast(ushort)((0x8000 & vu[4]) | 0x3FFE); 670 } 671 } 672 else if (!*vl) 673 { 718 vu[EXPONENTPOS] = cast(ushort)((0x8000 & vu[EXPONENTPOS]) | 0x3FFE); 719 } 720 } else if (!*vl) { 674 721 // value is +-0.0 675 722 exp = 0; 676 } 677 else 678 { // denormal 723 } else { 724 // denormal 679 725 int i = -0x3FFD; 680 681 do 682 { 726 do { 727 i--; 728 *vl <<= 1; 729 } while (*vl > 0); 730 exp = i; 731 vu[EXPONENTPOS] = cast(ushort)((0x8000 & vu[EXPONENTPOS]) | 0x3FFE); 732 } 733 } else static if(real.mant_dig==106) { 734 // 128-bit reals 735 throw new NotImplemented("frexp"); 736 } else { 737 // 64-bit reals 738 if (ex) { // If exponent is non-zero 739 if (ex == EXPMASK) { // infinity or NaN 740 if (*vl==0x7FF0_0000_0000_0000) { // positive infinity 741 exp = int.max; 742 } else if (*vl==0xFFF0_0000_0000_0000) { // negative infinity 743 exp = int.min; 744 } else { // NaN 745 *vl |= 0x0008_0000_0000_0000; // convert $(NAN)S to $(NAN)Q 746 exp = int.min; 747 } 748 } else { 749 exp = (ex - 0x3FE0) >>> 4; 750 ve[EXPONENTPOS] = (0x8000 & ve[EXPONENTPOS]) | 0x3FE0; 751 } 752 } else if (!(*vl & 0x7FFF_FFFF_FFFF_FFFF)) { 753 // value is +-0.0 754 exp = 0; 755 } else { 756 // denormal 757 ushort sgn; 758 sgn = (0x8000 & ve[EXPONENTPOS])| 0x3FE0; 759 *vl &= 0x7FFF_FFFF_FFFF_FFFF; 760 761 int i = -0x3FD+11; 762 do { 683 763 i--; 684 764 *vl <<= 1; 685 765 } while (*vl > 0); 686 766 exp = i; 687 vu[4] = cast(ushort)((0x8000 & vu[4]) | 0x3FFE); 767 ve[EXPONENTPOS] = sgn; 768 } 688 769 } 689 770 return value; … … 700 781 [-1.0, -.5, 1], 701 782 [2.0, .5, 2], 702 [155.67e20, 0x1.A5F1C2EB3FE4Fp-1, 74], // normal 703 [1.0e-320, 0.98829225, -1063], 704 [real.min, .5, -16381], 705 [real.min/2.0L, .5, -16382], // denormal 706 783 [double.min/2.0, .5, -1022], 707 784 [real.infinity,real.infinity,int.max], 708 785 [-real.infinity,-real.infinity,int.min], 709 786 [real.nan,real.nan,int.min], 710 787 [-real.nan,-real.nan,int.min], 711 712 // Don't really support signalling nan's in D713 //[real.nans,real.nan,int.min],714 //[-real.nans,-real.nan,int.min],715 788 ]; 789 716 790 int i; 717 791 718 for (i = 0; i < vals.length; i++) 719 { 792 for (i = 0; i < vals.length; i++) { 720 793 real x = vals[i][0]; 721 794 real e = vals[i][1]; … … 723 796 int eptr; 724 797 real v = frexp(x, eptr); 725 726 //printf("frexp(%Lg) = %.8Lg, should be %.8Lg, eptr = %d, should be %d\n", x, v, e, eptr, exp); 727 assert(mfeq(e, v, .0000001)); 798 // printf("frexp(%La) = %La, should be %La, eptr = %d, should be %d\n", x, v, e, eptr, exp); 799 assert(isIdentical(e, v)); 800 assert(exp == eptr); 801 802 } 803 static if (real.mant_dig == 64) { 804 static real extendedvals[][3] = [ // x,frexp,exp 805 [0x1.a5f1c2eb3fe4efp+73, 0x1.A5F1C2EB3FE4EFp-1, 74], // normal 806 [0x1.fa01712e8f0471ap-1064, 0x1.fa01712e8f0471ap-1, -1063], 807 [real.min, .5, -16381], 808 [real.min/2.0L, .5, -16382] // denormal 809 ]; 810 811 for (i = 0; i < extendedvals.length; i++) { 812 real x = extendedvals[i][0]; 813 real e = extendedvals[i][1]; 814 int exp = cast(int)extendedvals[i][2]; 815 int eptr; 816 real v = frexp(x, eptr); 817 assert(isIdentical(e, v)); 728 818 assert(exp == eptr); 729 } 730 } 731 819 820 } 821 } 822 } 732 823 733 824 /****************************************** … … 861 952 version (linux) 862 953 return std.c.math.scalbnl(x, n); 863 else 954 else version(D_InlineAsm_X86) { 955 asm { 956 fild n; 957 fld x; 958 fscale; 959 fstp st(1), st; 960 } 961 } else 864 962 throw new NotImplemented("scalbn"); 963 } 964 965 unittest { 966 assert(scalbn(-real.infinity, 5) == -real.infinity); 865 967 } 866 968 … … 1113 1215 * Rounds x to the nearest integer value, using the current rounding 1114 1216 * mode. 1217 * 1218 * This is generally the fastest method to convert a floating-point number 1219 * to an integer. Note that the results from this function 1220 * depend on the rounding mode, if the fractional part of x is exactly 0.5. 1221 * If using the default rounding mode (ties round to even integers) 1222 * lrint(4.5) == 4, lrint(5.5)==6. 1115 1223 */ 1116 1224 long lrint(real x) … … 1118 1226 version (linux) 1119 1227 return std.c.math.llrintl(x); 1228 else version(D_InlineAsm_X86) 1229 { 1230 long n; 1231 asm 1232 { 1233 fld x; 1234 fistp n; 1235 } 1236 return n; 1237 } 1120 1238 else 1121 1239 throw new NotImplemented("lrint"); … … 1184 1302 */ 1185 1303 1186 int isnan(real e) 1187 { 1188 ushort* pe = cast(ushort *)&e; 1189 ulong* ps = cast(ulong *)&e; 1304 int isnan(real x) 1305 { 1306 static if (real.mant_dig==double.mant_dig) { 1307 // 64-bit real 1308 ulong* p = cast(ulong *)&x; 1309 return (*p & 0x7FF0_0000 == 0x7FF0_0000) && *p & 0x000F_FFFF; 1310 } else { 1311 // 80-bit real 1312 ushort* pe = cast(ushort *)&x; 1313 ulong* ps = cast(ulong *)&x; 1190 1314 1191 1315 return (pe[4] & 0x7FFF) == 0x7FFF && 1192 1316 *ps & 0x7FFFFFFFFFFFFFFF; 1317 } 1193 1318 } 1194 1319 … … 1209 1334 int isfinite(real e) 1210 1335 { 1336 static if (real.mant_dig == double.mant_dig) { 1337 return isfinite(cast(double)e); 1338 } else { 1211 1339 ushort* pe = cast(ushort *)&e; 1212 1340 1213 1341 return (pe[4] & 0x7FFF) != 0x7FFF; 1342 } 1214 1343 } 1215 1344 … … 1253 1382 /// ditto 1254 1383 1255 int isnormal(real e) 1256 { 1257 ushort* pe = cast(ushort *)&e; 1258 long* ps = cast(long *)&e; 1384 int isnormal(real x) 1385 { 1386 static if (real.mant_dig == double.mant_dig) { 1387 return isNormal(cast(double)x); 1388 } else { 1389 ushort* pe = cast(ushort *)&x; 1390 long* ps = cast(long *)&x; 1259 1391 1260 1392 return (pe[4] & 0x7FFF) != 0x7FFF && *ps < 0; 1393 } 1261 1394 } 1262 1395 … … 1318 1451 int issubnormal(real e) 1319 1452 { 1453 static if (real.mant_dig == double.mant_dig) { 1454 return isSubnormal(cast(double)e); 1455 } else { 1320 1456 ushort* pe = cast(ushort *)&e; 1321 1457 long* ps = cast(long *)&e; … … 1323 1459 return (pe[4] & 0x7FFF) == 0 && *ps > 0; 1324 1460 } 1461 } 1325 1462 1326 1463 unittest … … 1338 1475 int isinf(real e) 1339 1476 { 1477 static if (real.mant_dig == double.mant_dig) { 1478 return ((*cast(ulong *)&x)&0x7FFF_FFFF_FFFF_FFFF) == 0x7FF8_0000_0000_0000; 1479 } else { 1340 1480 ushort* pe = cast(ushort *)&e; 1341 1481 ulong* ps = cast(ulong *)&e; 1342 1482 1343 1483 return (pe[4] & 0x7FFF) == 0x7FFF && 1344 *ps == 0x8000000000000000; 1484 *ps == 0x8000_0000_0000_0000; 1485 } 1345 1486 } 1346 1487 … … 1356 1497 1357 1498 /********************************* 1499 * Is the binary representation of x identical to y? 1500 * 1501 * Same as ==, except that positive and negative zero are not identical, 1502 * and two $(NAN)s are identical if they have the same 'payload'. 1503 */ 1504 1505 bool isIdentical(real x, real y) 1506 { 1507 long* pxs = cast(long *)&x; 1508 long* pys = cast(long *)&y; 1509 static if (real.mant_dig == double.mant_dig){ 1510 return pxs[0] == pys[0]; 1511 } else { 1512 ushort* pxe = cast(ushort *)&x; 1513 ushort* pye = cast(ushort *)&y; 1514 return pxe[4] == pye[4] && pxs[0] == pys[0]; 1515 } 1516 } 1517 1518 /********************************* 1358 1519 * Return 1 if sign bit of e is set, 0 if not. 1359 1520 */ 1360 1521 1361 int signbit(real e) 1362 { 1363 ubyte* pe = cast(ubyte *)&e; 1364 1365 //printf("e = %Lg\n", e); 1522 int signbit(real x) 1523 { 1524 static if (real.mant_dig == double.mant_dig) { 1525 return ((*cast(ulong *)&x) & 0x8000_0000_0000_0000) != 0; 1526 } else { 1527 ubyte* pe = cast(ubyte *)&x; 1366 1528 return (pe[9] & 0x80) != 0; 1529 } 1367 1530 } 1368 1531 … … 1415 1578 /****************************************** 1416 1579 * Creates a quiet NAN with the information from tagp[] embedded in it. 1580 * 1581 * BUGS: DMD always returns real.nan, ignoring the payload. 1417 1582 */ 1418 1583 real nan(char[] tagp) { return std.c.math.nanl(toStringz(tagp)); } … … 1485 1650 * Returns (x * y) + z, rounding only once according to the 1486 1651 * current rounding mode. 1652 * 1653 * BUGS: Not currently implemented - rounds twice. 1487 1654 */ 1488 1655 real fma(real x, real y, real z) { return (x * y) + z; } … … 1704 1871 } 1705 1872 1706 // Returns true if x is +0.0 (This function is used in unit tests)1707 bool isPosZero(real x)1708 {1709 return (x == 0) && (signbit(x) == 0);1710 }1711 1712 // Returns true if x is -0.0 (This function is used in unit tests)1713 bool isNegZero(real x)1714 {1715 return (x == 0) && signbit(x);1716 }1717 1718 1873 /************************************** 1719 1874 * To what precision is x equal to y? … … 1736 1891 /* Public Domain. Author: Don Clugston, 18 Aug 2005. 1737 1892 */ 1738 1739 1893 if (x == y) 1740 1894 return real.mant_dig; // ensure diff!=0, cope with INF. … … 1755 1909 // always 1 lower than we want, except that if bitsdiff==0, 1756 1910 // they could have 0 or 1 bits in common. 1757 int bitsdiff = ( ((pa[4]&0x7FFF) + (pb[4]&0x7FFF)-1)>>1) - pd[4]; 1758 1759 if (pd[4] == 0) 1911 static if (real.mant_dig==64) { // 80-bit reals 1912 const real POW2MANTDIG = 0x1p+63; // pow(2, real.mant_dig) 1913 const int EXPONENTPOS = 4; 1914 int bitsdiff = ( ((pa[EXPONENTPOS]&0x7FFF) + (pb[EXPONENTPOS]&0x7FFF)-1)>>1) 1915 - pd[EXPONENTPOS]; 1916 } else { // 64-bit reals 1917 const real POW2MANTDIG = 0x1p+53; 1918 version(LittleEndian) 1919 const int EXPONENTPOS = 3; 1920 else const int EXPONENTPOS = 0; 1921 int bitsdiff = ( ((pa[EXPONENTPOS]&0x7FF0) + (pb[EXPONENTPOS]&0x7FF0)-0x10)>>5) 1922 - (pd[EXPONENTPOS]&0x7FF0>>4); 1923 } 1924 if (pd[EXPONENTPOS] == 0) 1760 1925 { // Difference is denormal 1761 1926 // For denormals, we need to add the number of zeros that 1762 // lie at the start of diff's mantissa.1927 // lie at the start of diff's significand. 1763 1928 // We do this by multiplying by 2^real.mant_dig 1764 diff *= 0x1p+63;1765 return bitsdiff + real.mant_dig - pd[4];1929 diff *= POW2MANTDIG; 1930 return bitsdiff + real.mant_dig - pd[EXPONENTPOS]; 1766 1931 } 1767 1932 … … 1770 1935 1771 1936 // Avoid out-by-1 errors when factor is almost 2. 1772 return (bitsdiff == 0) ? (pa[4] == pb[4]) : 0; 1937 static if (real.mant_dig==64) 1938 { 1939 return (bitsdiff == 0) ? (pa[EXPONENTPOS] == pb[EXPONENTPOS]) : 0; 1940 } else { 1941 if (bitsdiff == 0 && (pa[EXPONENTPOS] ^ pb[EXPONENTPOS])&0x7FF0) return 1; 1942 else return 0; 1943 } 1773 1944 } 1774 1945 … … 1834 2005 version (Windows) 1835 2006 { 2007 // BUG: This code assumes a frame pointer in EBP. 1836 2008 asm // assembler by W. Bright 1837 2009 {
