Guest User

Untitled

a guest
Apr 9th, 2016
75
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. import java.util.ArrayList;
  2. import java.util.List;
  3.  
  4. /**
  5.  * Experimentations autour de nombre flottants en faisant varier le nombre de bits de la mantisse.
  6.  *
  7.  * @author Samuel DEVULDER Avril 2016
  8.  */
  9. public class FP extends Number implements Comparable<FP> {
  10.     // http://www.quinapalus.com/efunc.html
  11.  
  12.     private static final long serialVersionUID = 1L;
  13.     byte sign;
  14.     int exp;
  15.     long mantissa;
  16.  
  17.     static final int EXPONENT_BITS = 8;
  18.     static final int MANTISSA_BITS = 15;
  19.  
  20.     static long ONE_MSK = 1l << MANTISSA_BITS;
  21.  
  22.     static FP ZERO = new FP(0, 0, 0);
  23.     static FP LN2 = new FP(1, -1, (long) (Math.log(2) * ONE_MSK * 2 + .5));
  24.     static FP ONE = new FP(1, 0, 1 << MANTISSA_BITS);
  25.     static FP SQRT2 = new FP(1, 0, (long) (Math.sqrt(2) * ONE_MSK + .5));
  26.     static FP TWO = new FP(1, 1, 1 << MANTISSA_BITS);
  27.     static FP LN10 = new FP(1, 1, (long) (Math.log(10) * ONE_MSK / 2 + .5));
  28.     static FP E = new FP(1, 1, (long) (Math.exp(1) * ONE_MSK / 2 + .5));
  29.     static FP PI = new FP(1, 1, (long) (Math.PI * ONE_MSK / 2 + .5));
  30.     static FP TEN = new FP(1, 3, 10 << (MANTISSA_BITS - 3));
  31.     static FP MAX = new FP(1, 127, ONE_MSK * 2 - 1);
  32.  
  33.     static FP[] NUMS = { ZERO, LN2, ONE, SQRT2, TWO, LN10, E, PI, TEN, MAX };
  34.  
  35.     public static void main(String[] args) {
  36.         System.out.println("LN2=" + LN2);
  37.         System.out.println("ONE=" + ONE);
  38.         System.out.println("SQRT2=" + SQRT2);
  39.         System.out.println("TWO=" + TWO);
  40.         System.out.println("LN10=" + LN10);
  41.         System.out.println("PI=" + PI);
  42.         System.out.println("TEN=" + TEN);
  43.         System.out.println("MAX=" + MAX);
  44.         System.out.println("ONE+SQRT2=" + ONE.add(SQRT2));
  45.         System.out.println("ONE-SQRT2=" + ONE.sub(SQRT2));
  46.         System.out.println("SQRT2-SQRT2=" + SQRT2.sub(SQRT2));
  47.         System.out.println("SQRT2*SQRT2=" + SQRT2.mul(SQRT2));
  48.         System.out.println("SQRT2/SQRT2=" + SQRT2.div(SQRT2));
  49.  
  50.         System.out.println("SQRT2 % 1=" + SQRT2.mod(ONE));
  51.         System.out.println("SQRT2*TEN % LN2=" + SQRT2.mul(TEN).mod(LN2));
  52.  
  53.         System.out.println("ONE/MAX=" + ONE.div(MAX));
  54.         System.out.println("parse1=" + new FP("-314.1592653589E-2"));
  55.         System.out.println("parse2=" + new FP("3.141592653589"));
  56.  
  57.         for (FP x : NUMS) {
  58.             System.out.println("ln(" + x + ")=" + x.ln());
  59.             System.out.println("log10(" + x + ")=" + x.log10());
  60.             System.out.println("sqrt(" + x + ")=" + x.sqrt());
  61.             System.out.println("" + x + "²=" + x.square());
  62.             System.out.println("exp(" + x.neg() + ")=" + x.neg().exp());
  63.             System.out.println("exp(" + x + ")=" + x.exp());
  64.             System.out.println("sin(" + x + ")=" + x.sin());
  65.             System.out.println("cos(" + x + ")=" + x.cos());
  66.             System.out.println("sin²+cos²(" + x + ")=" + x.cos().square().add(x.sin().square()));
  67.             System.out.println("atan(" + x + ")=" + x.atan());
  68.         }
  69.  
  70.         // for (FP x = ONE; true;) {
  71.         // System.out.println(x);
  72.         // FP y = x.add(x);
  73.         // if (x.equals(y))
  74.         // break;
  75.         // x = y;
  76.         // }
  77.  
  78.         for (long mant = ONE_MSK; mant < 2 * ONE_MSK; ++mant) {
  79.             FP x = new FP(1, 0, mant);
  80.             x.exp();
  81.         }
  82.     }
  83.  
  84.     FP(int sign, int exp, long mantissa) {
  85.         build(sign, exp, mantissa);
  86.     }
  87.  
  88.     protected int sign() {
  89.         return sign;
  90.     }
  91.  
  92.     protected int exponent() {
  93.         return exp;
  94.     }
  95.  
  96.     protected long mantissa() {
  97.         return mantissa;
  98.     }
  99.  
  100.     public FP(double d) {
  101.         int sgn = d < 0 ? -1 : d > 0 ? 1 : 0;
  102.         int exp = Math.getExponent(d);
  103.         long man = (long) Math.scalb(sgn < 0 ? -d : d, MANTISSA_BITS - exp);
  104.         build(man == 0 ? 0 : sgn, exp, man);
  105.     }
  106.  
  107.     protected FP build(int sign, int exp, long mantissa) {
  108.         this.sign = (byte) sign;
  109.  
  110.         int EXP_MSK = (1 << (EXPONENT_BITS - 1)) - 1;
  111.         this.exp = (byte) (exp > EXP_MSK ? EXP_MSK : exp < -EXP_MSK ? -EXP_MSK : exp);
  112.         this.mantissa = mantissa & (ONE_MSK * 2 - 1);
  113.         if (sign != 0 && (mantissa & ONE_MSK) == 0)
  114.             throw new RuntimeException("Bad mantissa " + Long.toHexString(this.mantissa));
  115.         return this;
  116.     }
  117.  
  118.     public FP(String s_) {
  119.         int i = 0;
  120.         char[] s = s_.toCharArray();
  121.  
  122.         // read sign
  123.         int sgn = 1;
  124.         while (i < s.length && (s[i] == '-' || s[i] == '+')) {
  125.             if (s[i++] == '-')
  126.                 sgn = -sgn;
  127.         }
  128.  
  129.         // read int part
  130.         FP v = ZERO;
  131.         while (i < s.length && s[i] >= '0' && s[i] <= '9') {
  132.             v = v.mul(TEN).add(s[i++] - '0');
  133.         }
  134.  
  135.         // read decimal
  136.         if (i < s.length && s[i] == '.') {
  137.             FP div = ONE;
  138.             ++i;
  139.             while (i < s.length && s[i] >= '0' && s[i] <= '9') {
  140.                 div = div.div(TEN);
  141.                 v = v.add(div.mul(s[i++] - '0'));
  142.             }
  143.         }
  144.  
  145.         // read exponent
  146.         if (i < s.length && (s[i] == 'e' || s[i] == 'E')) {
  147.             ++i;
  148.  
  149.             int sgn2 = 1;
  150.             while (i < s.length && (s[i] == '-' || s[i] == '+')) {
  151.                 if (s[i++] == '-')
  152.                     sgn2 = -sgn2;
  153.             }
  154.  
  155.             FP e = ONE;
  156.             while (i < s.length && s[i] >= '0' && s[i] <= '9') {
  157.                 e = e.pow(10).mul(pow_tab[s[i++] - '0']);
  158.             }
  159.  
  160.             v = sgn2 < 0 ? v.div(e) : v.mul(e);
  161.         }
  162.  
  163.         if (sgn < 0)
  164.             v = v.neg();
  165.  
  166.         build(v.sign(), v.exponent(), v.mantissa());
  167.     }
  168.  
  169.     static FP[] pow_tab = { TEN.pow(0), TEN.pow(1), TEN.pow(2), TEN.pow(3), TEN.pow(4), TEN.pow(5), TEN.pow(6), TEN.pow(7), TEN.pow(8), TEN.pow(9) };
  170.  
  171.     @Override
  172.     public boolean equals(Object obj) {
  173.         return obj instanceof FP && compareTo((FP) obj) == 0;
  174.     }
  175.  
  176.     @Override
  177.     public int hashCode() {
  178.         if (sign == 0)
  179.             return 0;
  180.         return (int) ((sign * 31 + mantissa) * 31 + exp);
  181.     }
  182.  
  183.     @Override
  184.     public double doubleValue() {
  185.         if (sign() == 0)
  186.             return 0;
  187.         double t = mantissa() * Math.pow(2, exponent() - MANTISSA_BITS);
  188.         return sign() < 0 ? -t : t;
  189.     }
  190.  
  191.     @Override
  192.     public float floatValue() {
  193.         return (float) doubleValue();
  194.     }
  195.  
  196.     @Override
  197.     public int intValue() {
  198.         return (int) longValue();
  199.     }
  200.  
  201.     @Override
  202.     public long longValue() {
  203.         int sgn = sign();
  204.         if (sgn == 0)
  205.             return 0;
  206.         long val = mantissa() >>> (MANTISSA_BITS - exponent());
  207.         return sgn < 0 ? -val : val;
  208.     }
  209.  
  210.     public FP mul2() {
  211.         return new FP(sign(), exponent() + 1, mantissa());
  212.     }
  213.  
  214.     public FP div2() {
  215.         return new FP(sign(), exponent() - 1, mantissa());
  216.     }
  217.  
  218.     public FP floor() {
  219.         int exp = exponent();
  220.         if (exp < 0)
  221.             return ZERO;
  222.         if (exp > MANTISSA_BITS)
  223.             return this;
  224.         long m = /* 2*ONE_MSK */ -(ONE_MSK >>> exp);
  225.         return new FP(sign(), exp, mantissa() & m);
  226.     }
  227.  
  228.     static FP PRECISION;
  229.  
  230.     static {
  231.         FP x = ONE, y = new FP(1, -MANTISSA_BITS, 1 << MANTISSA_BITS);
  232.         while (x.compareTo(y) > 0) {
  233.             PRECISION = x;
  234.             x = x.div(TEN);
  235.         }
  236.     }
  237.  
  238.     public String toString() {
  239.         // return Double.toString(doubleValue());
  240.  
  241.         // http://stackoverflow.com/questions/2302969/how-to-implement-char-ftoafloat-num-without-sprintf-library-function-i
  242.         if (sign() == 0)
  243.             return "0";
  244.         StringBuilder sb = new StringBuilder();
  245.  
  246.         boolean neg = sign() < 0;
  247.         FP x = this.abs();
  248.         // if(x.mantissa!=0xFFFF) ++x.mantissa;
  249.         int m = 0, m1 = 0;
  250.         // while(TEN.pow(m+1).compareTo(x)<=0) ++m;
  251.         m = x.log10().intValue();
  252.         boolean useExp = (m >= 5 || (neg && m >= 3) || m <= -5);
  253.         if (neg)
  254.             sb.append('-');
  255.         // set up for scientific notation
  256.         if (useExp) {
  257.             if (m < 0)
  258.                 --m;
  259.             x = x.mul(TEN.pow(-m));
  260.             m1 = m;
  261.             m = 0;
  262.         }
  263.         if (m < 1.0) {
  264.             m = 0;
  265.         }
  266.         // convert the number
  267.         while (x.compareTo(PRECISION) > 0 || m >= 0) {
  268.             FP weight = TEN.pow(m);
  269.             if (weight.tst() > 0) {
  270.                 int digit = x.div(weight).intValue();
  271.                 x = x.sub(weight.mul(digit));
  272.                 sb.append((char) ('0' + digit));
  273.             }
  274.             if (m == 0 && x.tst() > 0)
  275.                 sb.append('.');
  276.             m--;
  277.         }
  278.         if (useExp) {
  279.             // convert the exponent
  280.             sb.append('e');
  281.             if (m1 > 0) {
  282.                 sb.append('+');
  283.             } else {
  284.                 sb.append('-');
  285.                 m1 = -m1;
  286.             }
  287.             if (m1 > 10) {
  288.                 sb.append((char) ('0' + m1 / 10));
  289.                 m1 = m1 % 10;
  290.             }
  291.             sb.append((char) ('0' + m1));
  292.         }
  293.         return sb.toString();
  294.     };
  295.  
  296.     public FP neg() {
  297.         return new FP(-sign(), exponent(), mantissa());
  298.     }
  299.  
  300.     public FP abs() {
  301.         return new FP(sign() == 0 ? 0 : 1, exponent(), mantissa());
  302.     }
  303.  
  304.     public FP mulSign(FP other) {
  305.         return new FP((other.sign() & sign()) == 0 ? 0 : ((other.sign() ^ sign()) | 1), exponent(), mantissa());
  306.     }
  307.  
  308.     public int tst() {
  309.         return sign();
  310.     }
  311.  
  312.     public int compareTo(FP other) {
  313.         int d = this.sign() - other.sign();
  314.         if (d != 0) {
  315.             return d;
  316.         }
  317.         if (this.sign() == 0)
  318.             return 0;
  319.         d = this.exponent() - other.exponent();
  320.         if (d != 0)
  321.             return d;
  322.         d = (int) (this.mantissa() - other.mantissa());
  323.         return d;
  324.     }
  325.  
  326.     public FP mul(FP other) {
  327.         if ((this.sign() & other.sign()) == 0)
  328.             return ZERO;
  329.         int sign = (this.sign() ^ other.sign()) | 1;
  330.         int exp = this.exponent() + other.exponent();
  331.         long mant = (this.mantissa() * other.mantissa()) >>> MANTISSA_BITS;
  332.         if ((mant & (2l << MANTISSA_BITS)) != 0) {
  333.             mant >>>= 1;
  334.             ++exp;
  335.         }
  336.         return new FP(mant == 0 ? 0 : sign, exp, mant);
  337.     }
  338.  
  339.     public FP mul(double v) {
  340.         return mul(new FP(v));
  341.     }
  342.  
  343.     public FP square() {
  344.         return mul(this);
  345.     }
  346.  
  347.     public FP pow(int n) {
  348.         boolean neg = n < 0;
  349.         if (neg)
  350.             n = -n;
  351.         FP x = this, y = ONE;
  352.         while (n != 0) {
  353.             if ((n & 1) != 0) {
  354.                 y = y.mul(x);
  355.             }
  356.             x = x.square();
  357.             n >>>= 1;
  358.         }
  359.         return neg ? y.inv() : y;
  360.     }
  361.  
  362.     public FP div(FP other) {
  363.         if (other.sign() == 0)
  364.             return MAX.mulSign(this).mulSign(other);
  365.         if (this.sign() == 0)
  366.             return ZERO;
  367.         int sign = (this.sign() ^ other.sign()) | 1;
  368.         int exp = this.exponent() - other.exponent();
  369.         long mant = (this.mantissa() << (1 + MANTISSA_BITS)) / other.mantissa();
  370.         if ((mant & (2l << MANTISSA_BITS)) != 0) {
  371.             mant >>>= 1;
  372.         } else {
  373.             --exp;
  374.         }
  375.         return new FP(sign, exp, mant);
  376.     }
  377.  
  378.     public FP mod(FP other) {
  379.         return sub(div(other).floor().mul(other));
  380.     }
  381.  
  382.     public FP inv() {
  383.         return ONE.div(this);
  384.     }
  385.  
  386.     public FP sub(FP other) {
  387.         return add(other.neg());
  388.     }
  389.  
  390.     public FP add(FP other) {
  391.         if (sign() == 0)
  392.             return other;
  393.         if (other.sign() == 0)
  394.             return this;
  395.  
  396.         FP small = this;
  397.         FP big = other;
  398.         if (small.exponent() == big.exponent()) {
  399.             if (small.mantissa() > big.mantissa()) {
  400.                 small = other;
  401.                 big = this;
  402.             }
  403.         } else if (small.exponent() > big.exponent()) {
  404.             small = other;
  405.             big = this;
  406.         }
  407.         int exp = big.exponent();
  408.         long mant = big.mantissa();
  409.         long delta = small.mantissa() >>> (big.exponent() - small.exponent());
  410.         if (big.sign() == small.sign()) {
  411.             mant += delta;
  412.             if ((mant & (2l << MANTISSA_BITS)) != 0) {
  413.                 mant >>>= 1;
  414.                 ++exp;
  415.             }
  416.         } else {
  417.             mant -= delta;
  418.             if (mant == 0)
  419.                 return ZERO;
  420.             while ((mant & (1l << MANTISSA_BITS)) == 0) {
  421.                 mant <<= 1;
  422.                 --exp;
  423.             }
  424.         }
  425.         return new FP(big.sign(), exp, mant);
  426.     }
  427.  
  428.     protected FP add(double v) {
  429.         return add(new FP(v));
  430.     }
  431.  
  432.     static protected FP[] ln = { new FP(8.690628917915396e-06), new FP(0.9992996219306662), new FP(-0.4907434587925273), new FP(0.2867076984634543), new FP(-0.1332213692732176),
  433.             new FP(0.03110469698575859) };
  434.  
  435.     public FP ln() {
  436.         if (sign() <= 0)
  437.             return MAX.neg();
  438.  
  439.         FP y = ZERO;
  440.         if (false) {
  441.             // table accurate up to 15 bits
  442.             FP x = new FP(1, 0, mantissa()).sub(ONE);
  443.             for (int i = ln.length; --i >= 0;)
  444.                 y = y.mul(x).add(ln[i]);
  445.         } else {
  446.             // exact algorithm log( [1..2[ )
  447.             // multiply mantissa without geting out of the [1..2[
  448.             // interval
  449.             long x = mantissa(), z = exp_tab[0];
  450.             for (int k = 1; k < exp_tab.length; ++k) {
  451.                 long t = x + (x >> k);
  452.                 if ((t & 2 * ONE_MSK) == 0) {
  453.                     x = t;
  454.                     z -= exp_tab[k];
  455.                 }
  456.             }
  457.             int exp = 0;
  458.             if (z != 0)
  459.                 while (z < ONE_MSK) {
  460.                     z <<= 1;
  461.                     --exp;
  462.                 }
  463.             y = new FP(z == 0 ? 0 : 1, exp, z);
  464.         }
  465.         int exp = this.exponent() < 0 ? -this.exponent() : this.exponent();
  466.         while (exp > 0) {
  467.             y = y.add(LN2);
  468.             --exp;
  469.         }
  470.         if (this.exponent() < 0)
  471.             y = y.neg();
  472.         return y;
  473.     }
  474.  
  475.     public FP log10() {
  476.         return ln().div(LN10);
  477.     }
  478.  
  479.     public FP sqrt() {
  480.         if (sign() <= 0)
  481.             return ZERO;
  482.  
  483.         long op = mantissa() << MANTISSA_BITS;
  484.         long one = 1l << (MANTISSA_BITS + MANTISSA_BITS);
  485.         long res = 0;
  486.         while (one != 0) {
  487.             if (op >= res + one) {
  488.                 op -= res + one;
  489.                 res += one << 1;
  490.             }
  491.             res >>>= 1;
  492.             one >>>= 2;
  493.         }
  494.         /* Do arithmetic rounding to nearest integer */
  495.         if (op > res) {
  496.             res++;
  497.         }
  498.  
  499.         FP x = new FP(1, this.exponent() >> 1, res);
  500.         if ((this.exponent() & 1) != 0)
  501.             x = x.mul(SQRT2);
  502.         return x;
  503.     }
  504.  
  505.     static long[] exp_tab;
  506.  
  507.     static {
  508.         List<Long> array = new ArrayList<Long>();
  509.         for (long k = 1, t = 0; (t = (long) (Math.log((k + 1.0) / k) * ONE_MSK + 0.5)) != 0; k <<= 1)
  510.             array.add(t);
  511.         exp_tab = new long[array.size()];
  512.         for (int i = exp_tab.length; --i >= 0;)
  513.             exp_tab[i] = array.get(i).longValue();
  514.     }
  515.  
  516.     public FP exp() {
  517.         // exp(2^x * y) = exp(y)^(2^x) = exp(2^0) * exp(2^-1)
  518.  
  519.         if (sign() == 0)
  520.             return ONE;
  521.  
  522.         // exp(y)
  523.         FP x = ONE;
  524.         if (false) {
  525.             FP y = E;
  526.             long m = mantissa(), msk = ONE_MSK;
  527.             while (m != 0 && !ONE.equals(y)) {
  528.                 if ((m & msk) != 0) {
  529.                     x = x.mul(y);
  530.                     m ^= msk;
  531.                 }
  532.                 y = y.sqrt();
  533.                 msk >>>= 1;
  534.             }
  535.         } else {
  536.             // optim
  537.             long z = mantissa(), y = ONE_MSK;
  538.             int exp = 0;
  539.             for (int k = 0; k < exp_tab.length; ++k) {
  540.                 long t = z - exp_tab[k];
  541.                 if (t >= 0) {
  542.                     z = t;
  543.                     y += y >> k;
  544.                     if ((y & (ONE_MSK * 2)) != 0) {
  545.                         y >>>= 1;
  546.                         ++exp;
  547.                     }
  548.                 }
  549.             }
  550.             x = new FP(1, exp, y);
  551.         }
  552.  
  553.         // exp(2^exponent)
  554.         int exp = exponent();
  555.         while (exp > 0 && !MAX.equals(x)) {
  556.             x = x.square();
  557.             --exp;
  558.         }
  559.         while (exp < 0 && !ONE.equals(x)) {
  560.             x = x.sqrt();
  561.             ++exp;
  562.         }
  563.  
  564.         return sign() < 0 ? x.inv() : x;
  565.     }
  566.  
  567.     static protected FP[] sin = { new FP(7.068518675814434e-06), new FP(0.9996898644339388), new FP(0.002193716170952744), new FP(-0.1722388650880223),
  568.             new FP(0.006097383673278212), new FP(0.005721724054854694) };
  569.  
  570.     public FP sin() {
  571.         boolean neg = sign() < 0;
  572.         FP x = abs().mod(PI.mul2());
  573.         if (x.compareTo(PI) >= 0) {
  574.             x = x.sub(PI.mul2());
  575.             if (x.sign() < 0) {
  576.                 neg = !neg;
  577.                 x = x.neg();
  578.             }
  579.         }
  580.         if (x.compareTo(PI.div2()) >= 0) {
  581.             x = PI.sub(x);
  582.         }
  583.         FP y = ZERO;
  584.         // table accurate up to 15 bits
  585.         for (int i = sin.length; --i >= 0;)
  586.             y = y.mul(x).add(sin[i]);
  587.         if (neg)
  588.             y = y.neg();
  589.         return y;
  590.     }
  591.  
  592.     static protected FP[] cos = { new FP(1.000007068162554), new FP(-0.0003343311503654495), new FP(-0.4974330510416236), new FP(-0.007249836999713618),
  593.             new FP(0.05103555758070047), new FP(-0.005721683674851457) };
  594.  
  595.     public FP cos() {
  596.         // return add(PI.div2()).sin();
  597.         boolean neg = false;
  598.         FP x = abs().mod(PI.mul2());
  599.         if (x.compareTo(PI) >= 0) {
  600.             x = PI.mul2().sub(x);
  601.         }
  602.         if (x.compareTo(PI.div2()) >= 0) {
  603.             x = PI.sub(x);
  604.             neg = true;
  605.         }
  606.         FP y = ZERO;
  607.         // table accurate up to 15 bits
  608.         for (int i = cos.length; --i >= 0;)
  609.             y = y.mul(x).add(cos[i]);
  610.         if (neg)
  611.             y = y.neg();
  612.         return y;
  613.     }
  614.  
  615.     public FP tan() {
  616.         return sin().div(cos());
  617.     }
  618.  
  619.     public FP atan() {
  620.         return atan2(ONE);
  621.     }
  622.  
  623.     static protected FP[] atan = { new FP(-0.0464964749), new FP(0.15931422), new FP(-0.327622764) };
  624.  
  625.     public FP atan2(FP x) {
  626.         // http://math.stackexchange.com/questions/1098487/atan2-faster-approximation
  627.         FP y = this;
  628.         FP a = x.abs(), b = y.abs();
  629.         if (a.compareTo(b) > 0) {
  630.             a = b;
  631.             b = x.abs();
  632.         }
  633.         FP s = a.square();
  634.         FP r = atan[0].mul(s).add(atan[1]).mul(s).add(atan[2]).mul(s).mul(a).add(a);
  635.         if (y.abs().compareTo(x.abs()) > 0)
  636.             r = PI.div2().sub(r);
  637.         if (x.sign() < 0)
  638.             r = PI.sub(r);
  639.         if (y.sign() < 0)
  640.             r = r.neg();
  641.         return r;
  642.     }
  643.  
  644. }
Advertisement
Add Comment
Please, Sign In to add comment