/d/phobos/std/math2.d
D | 954 lines | 598 code | 124 blank | 232 comment | 117 complexity | a82235be2d1190d3d73019a7693217ca MD5 | raw file
Possible License(s): GPL-2.0, AGPL-1.0
- /* This module is obsolete and will be removed eventually */
- /*
- * Copyright (c) 2002
- * Pavel "EvilOne" Minayev
- *
- * Permission to use, copy, modify, distribute and sell this software
- * and its documentation for any purpose is hereby granted without fee,
- * provided that the above copyright notice appear in all copies and
- * that both that copyright notice and this permission notice appear
- * in supporting documentation. Author makes no representations about
- * the suitability of this software for any purpose. It is provided
- * "as is" without express or implied warranty.
- * Source: $(PHOBOSSRC std/_math2.d)
- */
- /* NOTE: This file has been patched from the original DMD distribution to
- work with the GDC compiler.
- Modified by David Friedman, September 2007
- */
- module std.math2;
- private import std.math, std.string, std.c.stdlib, std.c.stdio;
- version(GNU)
- static import std.c.math;
- //debug=math2;
- /****************************************
- * compare floats with given precision
- */
- bool feq(real a, real b)
- {
- return feq(a, b, 0.000001);
- }
- bool feq(real a, real b, real eps)
- {
- return abs(a - b) <= eps;
- }
- /*********************************
- * Modulus
- */
- int abs(int n)
- {
- return n > 0 ? n : -n;
- }
- long abs(long n)
- {
- return n > 0 ? n : -n;
- }
- real abs(real n)
- {
- // just let the compiler handle it
- return std.math.fabs(n);
- }
- /*********************************
- * Square
- */
- int sqr(int n)
- {
- return n * n;
- }
- long sqr(long n)
- {
- return n * n;
- }
- real sqr(real n)
- {
- return n * n;
- }
- unittest
- {
- assert(sqr(sqr(3)) == 81);
- }
- private ushort fp_cw_chop = 7999;
- /*********************************
- * Integer part
- */
- real trunc(real n)
- {
- version (GNU_Need_trunc) {
- return n >= 0 ? std.math.floor(n) : std.math.ceil(n);
- } else version (GNU) {
- return std.c.math.truncl(n);
- } else {
- ushort cw;
- asm
- {
- fstcw cw;
- fldcw fp_cw_chop;
- fld n;
- frndint;
- fldcw cw;
- }
- }
- }
- unittest
- {
- assert(feq(trunc(+123.456), +123.0L));
- assert(feq(trunc(-123.456), -123.0L));
- }
- /*********************************
- * Fractional part
- */
- real frac(real n)
- {
- return n - trunc(n);
- }
- unittest
- {
- assert(feq(frac(+123.456), +0.456L));
- assert(feq(frac(-123.456), -0.456L));
- }
- /*********************************
- * Sign
- */
- int sign(int n)
- {
- return (n > 0 ? +1 : (n < 0 ? -1 : 0));
- }
- unittest
- {
- assert(sign(0) == 0);
- assert(sign(+666) == +1);
- assert(sign(-666) == -1);
- }
- int sign(long n)
- {
- return (n > 0 ? +1 : (n < 0 ? -1 : 0));
- }
- unittest
- {
- assert(sign(0) == 0);
- assert(sign(+666L) == +1);
- assert(sign(-666L) == -1);
- }
- int sign(real n)
- {
- return (n > 0 ? +1 : (n < 0 ? -1 : 0));
- }
- unittest
- {
- assert(sign(0.0L) == 0);
- assert(sign(+123.456L) == +1);
- assert(sign(-123.456L) == -1);
- }
- /**********************************************************
- * Cycles <-> radians <-> grads <-> degrees conversions
- */
- real cycle2deg(real c)
- {
- return c * 360;
- }
- real cycle2rad(real c)
- {
- return c * PI * 2;
- }
- real cycle2grad(real c)
- {
- return c * 400;
- }
- real deg2cycle(real d)
- {
- return d / 360;
- }
- real deg2rad(real d)
- {
- return d / 180 * PI;
- }
- real deg2grad(real d)
- {
- return d / 90 * 100;
- }
- real rad2deg(real r)
- {
- return r / PI * 180;
- }
- real rad2cycle(real r)
- {
- return r / (PI * 2);
- }
- real rad2grad(real r)
- {
- return r / PI * 200;
- }
- real grad2deg(real g)
- {
- return g / 100 * 90;
- }
- real grad2cycle(real g)
- {
- return g / 400;
- }
- real grad2rad(real g)
- {
- return g / 200 * PI;
- }
- unittest
- {
- assert(feq(cycle2deg(0.5), 180));
- assert(feq(cycle2rad(0.5), PI));
- assert(feq(cycle2grad(0.5), 200));
- assert(feq(deg2cycle(180), 0.5));
- assert(feq(deg2rad(180), PI));
- assert(feq(deg2grad(180), 200));
- assert(feq(rad2deg(PI), 180));
- assert(feq(rad2cycle(PI), 0.5));
- assert(feq(rad2grad(PI), 200));
- assert(feq(grad2deg(200), 180));
- assert(feq(grad2cycle(200), 0.5));
- assert(feq(grad2rad(200), PI));
- }
- /************************************
- * Arithmetic average of values
- */
- real avg(real[] n)
- {
- real result = 0;
- for (size_t i = 0; i < n.length; i++)
- result += n[i];
- return result / n.length;
- }
- unittest
- {
- static real[4] n = [ 1, 2, 4, 5 ];
- assert(feq(avg(n), 3));
- }
- /*************************************
- * Sum of values
- */
- int sum(int[] n)
- {
- long result = 0;
- for (size_t i = 0; i < n.length; i++)
- result += n[i];
- return cast(int)result;
- }
- unittest
- {
- static int[3] n = [ 1, 2, 3 ];
- assert(sum(n) == 6);
- }
- long sum(long[] n)
- {
- long result = 0;
- for (size_t i = 0; i < n.length; i++)
- result += n[i];
- return result;
- }
- unittest
- {
- static long[3] n = [ 1, 2, 3 ];
- assert(sum(n) == 6);
- }
- real sum(real[] n)
- {
- real result = 0;
- for (size_t i = 0; i < n.length; i++)
- result += n[i];
- return result;
- }
- unittest
- {
- static real[3] n = [ 1, 2, 3 ];
- assert(feq(sum(n), 6));
- }
- /*************************************
- * The smallest value
- */
- int min(int[] n)
- {
- int result = int.max;
- for (size_t i = 0; i < n.length; i++)
- if (n[i] < result)
- result = n[i];
- return result;
- }
- unittest
- {
- static int[3] n = [ 2, -1, 0 ];
- assert(min(n) == -1);
- }
- long min(long[] n)
- {
- long result = long.max;
- for (size_t i = 0; i < n.length; i++)
- if (n[i] < result)
- result = n[i];
- return result;
- }
- unittest
- {
- static long[3] n = [ 2, -1, 0 ];
- assert(min(n) == -1);
- }
- real min(real[] n)
- {
- real result = real.max;
- for (size_t i = 0; i < n.length; i++)
- {
- if (n[i] < result)
- result = n[i];
- }
- return result;
- }
- unittest
- {
- static real[3] n = [ 2.0, -1.0, 0.0 ];
- assert(feq(min(n), -1));
- }
- int min(int a, int b)
- {
- return a < b ? a : b;
- }
- unittest
- {
- assert(min(1, 2) == 1);
- }
- long min(long a, long b)
- {
- return a < b ? a : b;
- }
- unittest
- {
- assert(min(1L, 2L) == 1);
- }
- real min(real a, real b)
- {
- return a < b ? a : b;
- }
- unittest
- {
- assert(feq(min(1.0L, 2.0L), 1.0L));
- }
- /*************************************
- * The largest value
- */
- int max(int[] n)
- {
- int result = int.min;
- for (size_t i = 0; i < n.length; i++)
- if (n[i] > result)
- result = n[i];
- return result;
- }
- unittest
- {
- static int[3] n = [ 0, 2, -1 ];
- assert(max(n) == 2);
- }
- long max(long[] n)
- {
- long result = long.min;
- for (size_t i = 0; i < n.length; i++)
- if (n[i] > result)
- result = n[i];
- return result;
- }
- unittest
- {
- static long[3] n = [ 0, 2, -1 ];
- assert(max(n) == 2);
- }
- real max(real[] n)
- {
- real result = real.min;
- for (size_t i = 0; i < n.length; i++)
- if (n[i] > result)
- result = n[i];
- return result;
- }
- unittest
- {
- static real[3] n = [ 0.0, 2.0, -1.0 ];
- assert(feq(max(n), 2));
- }
- int max(int a, int b)
- {
- return a > b ? a : b;
- }
- unittest
- {
- assert(max(1, 2) == 2);
- }
- long max(long a, long b)
- {
- return a > b ? a : b;
- }
- unittest
- {
- assert(max(1L, 2L) == 2);
- }
- real max(real a, real b)
- {
- return a > b ? a : b;
- }
- unittest
- {
- assert(feq(max(1.0L, 2.0L), 2.0L));
- }
- /*************************************
- * Arccotangent
- */
- real acot(real x)
- {
- return std.math.tan(1.0 / x);
- }
- unittest
- {
- assert(feq(acot(cot(0.000001)), 0.000001));
- }
- /*************************************
- * Arcsecant
- */
- real asec(real x)
- {
- return std.math.cos(1.0 / x);
- }
- /*************************************
- * Arccosecant
- */
- real acosec(real x)
- {
- return std.math.sin(1.0 / x);
- }
- /*************************************
- * Tangent
- */
- /+
- real tan(real x)
- {
- asm
- {
- fld x;
- fptan;
- fstp ST(0);
- fwait;
- }
- }
- unittest
- {
- assert(feq(tan(PI / 3), std.math.sqrt(3)));
- }
- +/
- /*************************************
- * Cotangent
- */
- real cot(real x)
- {
- version(GNU) {
- // %% is the asm below missing fld1?
- return 1/std.c.math.tanl(x);
- } else {
- asm
- {
- fld x;
- fptan;
- fdivrp;
- fwait;
- }
- }
- }
- unittest
- {
- assert(feq(cot(PI / 6), std.math.sqrt(3.0L)));
- }
- /*************************************
- * Secant
- */
- real sec(real x)
- {
- version(GNU) {
- return 1/std.c.math.cosl(x);
- } else {
- asm
- {
- fld x;
- fcos;
- fld1;
- fdivrp;
- fwait;
- }
- }
- }
- /*************************************
- * Cosecant
- */
- real cosec(real x)
- {
- version(GNU) {
- // %% is the asm below missing fld1?
- return 1/std.c.math.sinl(x);
- } else {
- asm
- {
- fld x;
- fsin;
- fld1;
- fdivrp;
- fwait;
- }
- }
- }
- /*********************************************
- * Extract mantissa and exponent from float
- */
- /+
- real frexp(real x, out int exponent)
- {
- version (GNU) {
- return std.c.math.frexpl(x, & exponent);
- } else {
- asm
- {
- fld x;
- mov EDX, exponent;
- mov dword ptr [EDX], 0;
- ftst;
- fstsw AX;
- fwait;
- sahf;
- jz done;
- fxtract;
- fxch;
- fistp dword ptr [EDX];
- fld1;
- fchs;
- fxch;
- fscale;
- inc dword ptr [EDX];
- fstp ST(1);
- done:
- fwait;
- }
- }
- }
- unittest
- {
- int exponent;
- real mantissa = frexp(123.456, exponent);
- assert(feq(mantissa * std.math.pow(2.0L, cast(real)exponent), 123.456));
- }
- +/
- /*************************************
- * Hyperbolic cotangent
- */
- real coth(real x)
- {
- return 1 / std.math.tanh(x);
- }
- unittest
- {
- real r1 = coth(1);
- real r2 = std.math.sinh(1);
- real r3 = std.math.tanh(1);
- real r4 = coth(1);
- printf("%0.5Lg %0.5Lg %0.5Lg %0.5Lg\n", r1, r2, r3, r4);
- printf("%0.5g %0.5g %0.5g %0.5g\n",
- coth(1), std.math.sinh(1), std.math.tanh(1), coth(1));
- assert(feq(coth(1), std.math.cosh(1) / std.math.sinh(1)));
- }
- /*************************************
- * Hyperbolic secant
- */
- real sech(real x)
- {
- return 1 / std.math.cosh(x);
- }
- /*************************************
- * Hyperbolic cosecant
- */
- real cosech(real x)
- {
- return 1 / std.math.sinh(x);
- }
- /*************************************
- * Hyperbolic arccosine
- */
- /+
- real acosh(real x)
- {
- if (x <= 1)
- return 0;
- else if (x > 1.0e10)
- return log(2) + log(x);
- else
- return log(x + std.math.sqrt((x - 1) * (x + 1)));
- }
- unittest
- {
- assert(acosh(0.5) == 0);
- assert(feq(acosh(std.math.cosh(3)), 3));
- }
- +/
- /*************************************
- * Hyperbolic arcsine
- */
- /+
- real asinh(real x)
- {
- if (!x)
- return 0;
- else if (x > 1.0e10)
- return log(2) + log(1.0e10);
- else if (x < -1.0e10)
- return -log(2) - log(1.0e10);
- else
- {
- real z = x * x;
- return x > 0 ?
- std.math.log1p(x + z / (1.0 + std.math.sqrt(1.0 + z))) :
- -std.math.log1p(-x + z / (1.0 + std.math.sqrt(1.0 + z)));
- }
- }
- unittest
- {
- assert(asinh(0) == 0);
- assert(feq(asinh(std.math.sinh(3)), 3));
- }
- +/
- /*************************************
- * Hyperbolic arctangent
- */
- /+
- real atanh(real x)
- {
- if (!x)
- return 0;
- else
- {
- if (x >= 1)
- return real.max;
- else if (x <= -1)
- return -real.max;
- else
- return x > 0 ?
- 0.5 * std.math.log1p((2.0 * x) / (1.0 - x)) :
- -0.5 * std.math.log1p((-2.0 * x) / (1.0 + x));
- }
- }
- unittest
- {
- assert(atanh(0) == 0);
- assert(feq(atanh(std.math.tanh(0.5)), 0.5));
- }
- +/
- /*************************************
- * Hyperbolic arccotangent
- */
- real acoth(real x)
- {
- return 1 / acot(x);
- }
- unittest
- {
- assert(feq(acoth(coth(0.01)), 100));
- }
- /*************************************
- * Hyperbolic arcsecant
- */
- real asech(real x)
- {
- return 1 / asec(x);
- }
- /*************************************
- * Hyperbolic arccosecant
- */
- real acosech(real x)
- {
- return 1 / acosec(x);
- }
- /*************************************
- * Convert string to float
- */
- real atof(char[] s)
- {
- if (!s.length)
- return real.nan;
- real result = 0;
- size_t i = 0;
- while (s[i] == '\t' || s[i] == ' ')
- if (++i >= s.length)
- return real.nan;
- bool neg = false;
- if (s[i] == '-')
- {
- neg = true;
- i++;
- }
- else if (s[i] == '+')
- i++;
- if (i >= s.length)
- return real.nan;
- bool hex;
- if (s[s.length - 1] == 'h')
- {
- hex = true;
- s.length = s.length - 1;
- }
- else if (i + 1 < s.length && s[i] == '0' && s[i+1] == 'x')
- {
- hex = true;
- i += 2;
- if (i >= s.length)
- return real.nan;
- }
- else
- hex = false;
- while (s[i] != '.')
- {
- if (hex)
- {
- if ((s[i] == 'p' || s[i] == 'P'))
- break;
- result *= 0x10;
- }
- else
- {
- if ((s[i] == 'e' || s[i] == 'E'))
- break;
- result *= 10;
- }
- if (s[i] >= '0' && s[i] <= '9')
- result += s[i] - '0';
- else if (hex)
- {
- if (s[i] >= 'a' && s[i] <= 'f')
- result += s[i] - 'a' + 10;
- else if (s[i] >= 'A' && s[i] <= 'F')
- result += s[i] - 'A' + 10;
- else
- return real.nan;
- }
- else
- return real.nan;
- if (++i >= s.length)
- goto done;
- }
- if (s[i] == '.')
- {
- if (++i >= s.length)
- goto done;
- ulong k = 1;
- while (true)
- {
- if (hex)
- {
- if ((s[i] == 'p' || s[i] == 'P'))
- break;
- result *= 0x10;
- }
- else
- {
- if ((s[i] == 'e' || s[i] == 'E'))
- break;
- result *= 10;
- }
- k *= (hex ? 0x10 : 10);
- if (s[i] >= '0' && s[i] <= '9')
- result += s[i] - '0';
- else if (hex)
- {
- if (s[i] >= 'a' && s[i] <= 'f')
- result += s[i] - 'a' + 10;
- else if (s[i] >= 'A' && s[i] <= 'F')
- result += s[i] - 'A' + 10;
- else
- return real.nan;
- }
- else
- return real.nan;
- if (++i >= s.length)
- {
- result /= k;
- goto done;
- }
- }
- result /= k;
- }
- if (++i >= s.length)
- return real.nan;
- bool eneg = false;
- if (s[i] == '-')
- {
- eneg = true;
- i++;
- }
- else if (s[i] == '+')
- i++;
- if (i >= s.length)
- return real.nan;
- int e = 0;
- while (i < s.length)
- {
- e *= 10;
- if (s[i] >= '0' && s[i] <= '9')
- e += s[i] - '0';
- else
- return real.nan;
- i++;
- }
- if (eneg)
- e = -e;
- result *= std.math.pow(hex ? 2.0L : 10.0L, cast(real)e);
- done:
- return neg ? -result : result;
- }
- unittest
- {
- assert(feq(atof("123"), 123));
- assert(feq(atof("+123"), +123));
- assert(feq(atof("-123"), -123));
- assert(feq(atof("123e2"), 12300));
- assert(feq(atof("123e+2"), 12300));
- assert(feq(atof("123e-2"), 1.23));
- assert(feq(atof("123."), 123));
- assert(feq(atof("123.E-2"), 1.23));
- assert(feq(atof(".456"), .456));
- assert(feq(atof("123.456"), 123.456));
- assert(feq(atof("1.23456E+2"), 123.456));
- //assert(feq(atof("1A2h"), 1A2h));
- //assert(feq(atof("1a2h"), 1a2h));
- assert(feq(atof("0x1A2"), 0x1A2));
- assert(feq(atof("0x1a2p2"), 0x1a2p2));
- assert(feq(atof("0x1a2p+2"), 0x1a2p+2));
- assert(feq(atof("0x1a2p-2"), 0x1a2p-2));
- assert(feq(atof("0x1A2.3B4"), 0x1A2.3B4p0));
- assert(feq(atof("0x1a2.3b4P2"), 0x1a2.3b4P2));
- }