Guest User

Experimatation floating-point

a guest
Apr 7th, 2016
83
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. /**
  2.  * Experimentations autour de nombre flottants en faisant varier le nombre de
  3.  * bits de la mantisse.
  4.  *
  5.  * @author Samuel DEVULDER Avril 2016
  6.  */
  7. public class FP extends Number implements Comparable<FP> {
  8.     // http://www.quinapalus.com/efunc.html
  9.  
  10.     private static final long serialVersionUID = 1L;
  11.     byte sign, exp;
  12.     long mantissa;
  13.  
  14.     static final int BITS = 15;
  15.  
  16.     static long ONE_MSK = 1l << BITS;
  17.  
  18.     static FP ZERO = new FP(0, 0, 0);
  19.     static FP LN2 = new FP(1, -1, (long) (Math.log(2) * ONE_MSK * 2 + .5));
  20.     static FP ONE = new FP(1, 0, 1 << BITS);
  21.     static FP SQRT2 = new FP(1, 0, (long) (Math.sqrt(2) * ONE_MSK + .5));
  22.     static FP TWO = new FP(1, 1, 1 << BITS);
  23.     static FP LN10 = new FP(1, 1, (long) (Math.log(10) * ONE_MSK / 2 + .5));
  24.     static FP E = new FP(1, 1, (long) (Math.exp(1) * ONE_MSK / 2 + .5));
  25.     static FP PI = new FP(1, 1, (long) (Math.PI * ONE_MSK / 2 + .5));
  26.     static FP TEN = new FP(1, 3, 10 << (BITS - 3));
  27.     static FP MAX = new FP(1, 127, ONE_MSK * 2 - 1);
  28.  
  29.     public static void main(String[] args) {
  30.         System.out.println("LN2=" + LN2);
  31.         System.out.println("ONE=" + ONE);
  32.         System.out.println("SQRT2=" + SQRT2);
  33.         System.out.println("TWO=" + TWO);
  34.         System.out.println("LN10=" + LN10);
  35.         System.out.println("PI=" + PI);
  36.         System.out.println("TEN=" + TEN);
  37.         System.out.println("MAX=" + MAX);
  38.         System.out.println("ONE+SQRT2=" + ONE.add(SQRT2));
  39.         System.out.println("ONE-SQRT2=" + ONE.sub(SQRT2));
  40.         System.out.println("SQRT2-SQRT2=" + SQRT2.sub(SQRT2));
  41.         System.out.println("SQRT2*SQRT2=" + SQRT2.mul(SQRT2));
  42.         System.out.println("SQRT2/SQRT2=" + SQRT2.div(SQRT2));
  43.         System.out.println("ONE/MAX=" + ONE.div(MAX));
  44.         System.out.println("parse1=" + new FP("-314.1592653589E-2"));
  45.         System.out.println("parse2=" + new FP("3.141592653589"));
  46.  
  47.         System.out.println("ln(2)=" + TWO.ln());
  48.         System.out.println("ln(10)=" + TEN.ln());
  49.  
  50.         System.out.println("log10(2)=" + TWO.log10());
  51.         System.out.println("log10(10)=" + TEN.log10());
  52.  
  53.         System.out.println("sqrt(2)=" + TWO.sqrt());
  54.         System.out.println("sqrt(10)=" + TEN.sqrt());
  55.  
  56.         System.out.println("exp(-2)=" + TWO.neg().exp());
  57.         System.out.println("exp(-1)=" + ONE.neg().exp());
  58.         System.out.println("exp(0)=" + ZERO.exp());
  59.         System.out.println("exp(1)=" + ONE.exp());
  60.         System.out.println("exp(2)=" + TWO.exp());
  61.         System.out.println("exp(ln2)=" + LN2.exp());
  62.         System.out.println("exp(ln10)=" + LN10.exp());
  63.     }
  64.  
  65.     FP(int sign, int exp, long mantissa) {
  66.         build(sign, exp, mantissa);
  67.     }
  68.  
  69.     protected int sign() {
  70.         return sign;
  71.     }
  72.  
  73.     protected int exponent() {
  74.         return exp;
  75.     }
  76.  
  77.     protected long mantissa() {
  78.         return mantissa;
  79.     }
  80.  
  81.     public FP(double d) {
  82.         int sgn = d < 0 ? -1 : d > 0 ? 1 : 0;
  83.         int exp = Math.getExponent(d);
  84.         int man = (int) Math.scalb(sgn < 0 ? -d : d, BITS - exp);
  85.         build(man == 0 ? 0 : sgn, exp, man);
  86.     }
  87.  
  88.     protected FP build(int sign, int exp, long mantissa) {
  89.         this.sign = (byte) sign;
  90.         this.exp = (byte) exp;
  91.         this.mantissa = mantissa & (ONE_MSK * 2 - 1);
  92.         if (sign != 0 && (mantissa & ONE_MSK) == 0)
  93.             throw new RuntimeException("Bad mantissa "
  94.                     + Long.toHexString(this.mantissa));
  95.         return this;
  96.     }
  97.  
  98.     public FP(String s_) {
  99.         int i = 0;
  100.         char[] s = s_.toCharArray();
  101.  
  102.         // read sign
  103.         int sgn = 1;
  104.         while (i < s.length && (s[i] == '-' || s[i] == '+')) {
  105.             if (s[i++] == '-')
  106.                 sgn = -sgn;
  107.         }
  108.  
  109.         // read int part
  110.         FP v = ZERO;
  111.         while (i < s.length && s[i] >= '0' && s[i] <= '9') {
  112.             v = v.mul(TEN).add(s[i++] - '0');
  113.         }
  114.  
  115.         // read decimal
  116.         if (i < s.length && s[i] == '.') {
  117.             FP div = ONE;
  118.             ++i;
  119.             while (i < s.length && s[i] >= '0' && s[i] <= '9') {
  120.                 div = div.div(TEN);
  121.                 v = v.add(div.mul(s[i++] - '0'));
  122.             }
  123.         }
  124.  
  125.         // read exponent
  126.         if (i < s.length && (s[i] == 'e' || s[i] == 'E')) {
  127.             ++i;
  128.  
  129.             int sgn2 = 1;
  130.             while (i < s.length && (s[i] == '-' || s[i] == '+')) {
  131.                 if (s[i++] == '-')
  132.                     sgn2 = -sgn2;
  133.             }
  134.  
  135.             FP e = ONE;
  136.             while (i < s.length && s[i] >= '0' && s[i] <= '9') {
  137.                 e = e.pow(10).mul(pow_tab[s[i++] - '0']);
  138.             }
  139.  
  140.             v = sgn2 < 0 ? v.div(e) : v.mul(e);
  141.         }
  142.  
  143.         if (sgn < 0)
  144.             v = v.neg();
  145.  
  146.         build(v.sign(), v.exponent(), v.mantissa());
  147.     }
  148.  
  149.     static FP[] pow_tab = { TEN.pow(0), TEN.pow(1), TEN.pow(2), TEN.pow(3),
  150.             TEN.pow(4), TEN.pow(5), TEN.pow(6), TEN.pow(7), TEN.pow(8),
  151.             TEN.pow(9) };
  152.  
  153.     @Override
  154.     public boolean equals(Object obj) {
  155.         return obj instanceof FP && compareTo((FP) obj) == 0;
  156.     }
  157.  
  158.     @Override
  159.     public int hashCode() {
  160.         if (sign == 0)
  161.             return 0;
  162.         return (int) ((sign * 31 + mantissa) * 31 + exp);
  163.     }
  164.  
  165.     @Override
  166.     public double doubleValue() {
  167.         if (sign() == 0)
  168.             return 0;
  169.         double t = mantissa() * Math.pow(2, exponent() - BITS);
  170.         return sign() < 0 ? -t : t;
  171.     }
  172.  
  173.     @Override
  174.     public float floatValue() {
  175.         return (float) doubleValue();
  176.     }
  177.  
  178.     @Override
  179.     public int intValue() {
  180.         return (int) longValue();
  181.     }
  182.  
  183.     @Override
  184.     public long longValue() {
  185.         int sgn = sign();
  186.         if (sgn == 0)
  187.             return 0;
  188.         long val = mantissa() >>> (BITS - exponent());
  189.         return sgn < 0 ? -val : val;
  190.     }
  191.  
  192.     public FP floor() {
  193.         int exp = exponent();
  194.         if (exp < 0)
  195.             return ZERO;
  196.         if (exp > BITS)
  197.             return this;
  198.         long m = (2l << BITS) - ((1l << BITS) >>> exp);
  199.         return new FP(sign(), exp, mantissa() & m);
  200.     }
  201.  
  202.     static FP PRECISION;
  203.  
  204.     static {
  205.         FP x = ONE, y = new FP(1, -BITS, 1 << BITS);
  206.         while (x.compareTo(y) > 0) {
  207.             PRECISION = x;
  208.             x = x.div(TEN);
  209.         }
  210.     }
  211.  
  212.     public String toString() {
  213.         // return Double.toString(doubleValue());
  214.  
  215.         // http://stackoverflow.com/questions/2302969/how-to-implement-char-ftoafloat-num-without-sprintf-library-function-i
  216.         if (sign() == 0)
  217.             return "0";
  218.         StringBuilder sb = new StringBuilder();
  219.  
  220.         boolean neg = sign() < 0;
  221.         FP x = this.abs();
  222.         // if(x.mantissa!=0xFFFF) ++x.mantissa;
  223.         int m = 0, m1 = 0;
  224.         // while(TEN.pow(m+1).compareTo(x)<=0) ++m;
  225.         m = x.log10().intValue();
  226.         boolean useExp = (m >= 5 || (neg && m >= 3) || m <= -5);
  227.         if (neg)
  228.             sb.append('-');
  229.         // set up for scientific notation
  230.         if (useExp) {
  231.             if (m < 0)
  232.                 --m;
  233.             x = x.mul(TEN.pow(-m));
  234.             m1 = m;
  235.             m = 0;
  236.         }
  237.         if (m < 1.0) {
  238.             m = 0;
  239.         }
  240.         // convert the number
  241.         while (x.compareTo(PRECISION) > 0 || m >= 0) {
  242.             FP weight = TEN.pow(m);
  243.             if (weight.tst() > 0) {
  244.                 int digit = x.div(weight).intValue();
  245.                 x = x.sub(weight.mul(digit));
  246.                 sb.append((char) ('0' + digit));
  247.             }
  248.             if (m == 0 && x.tst() > 0)
  249.                 sb.append('.');
  250.             m--;
  251.         }
  252.         if (useExp) {
  253.             // convert the exponent
  254.             sb.append('e');
  255.             if (m1 > 0) {
  256.                 sb.append('+');
  257.             } else {
  258.                 sb.append('-');
  259.                 m1 = -m1;
  260.             }
  261.             if (m1 > 10) {
  262.                 sb.append((char) ('0' + m1 / 10));
  263.                 m1 = m1 % 10;
  264.             }
  265.             sb.append((char) ('0' + m1));
  266.         }
  267.         return sb.toString();
  268.     };
  269.  
  270.     public FP neg() {
  271.         return new FP(-sign(), exponent(), mantissa());
  272.     }
  273.  
  274.     public FP abs() {
  275.         return new FP(sign() == 0 ? 0 : 1, exponent(), mantissa());
  276.     }
  277.  
  278.     public FP mulSign(FP other) {
  279.         return new FP((other.sign() & sign()) == 0 ? 0
  280.                 : ((other.sign() ^ sign()) | 1), exponent(), mantissa());
  281.     }
  282.  
  283.     public int tst() {
  284.         return sign();
  285.     }
  286.  
  287.     public int compareTo(FP other) {
  288.         int d = this.sign() - other.sign();
  289.         if (d != 0) {
  290.             return d;
  291.         }
  292.         if (this.sign() == 0)
  293.             return 0;
  294.         d = this.exponent() - other.exponent();
  295.         if (d != 0)
  296.             return d;
  297.         d = (int) (this.mantissa() - other.mantissa());
  298.         return d;
  299.     }
  300.  
  301.     public FP mul(FP other) {
  302.         if ((this.sign() & other.sign()) == 0)
  303.             return ZERO;
  304.         int sign = (this.sign() ^ other.sign()) | 1;
  305.         int exp = this.exponent() + other.exponent();
  306.         long mant = (this.mantissa() * other.mantissa()) >>> BITS;
  307.         if ((mant & (2l << BITS)) != 0) {
  308.             mant >>>= 1;
  309.             ++exp;
  310.         }
  311.         return new FP(mant == 0 ? 0 : sign, exp, mant);
  312.     }
  313.  
  314.     public FP mul(double v) {
  315.         return mul(new FP(v));
  316.     }
  317.  
  318.     public FP square() {
  319.         return mul(this);
  320.     }
  321.  
  322.     public FP pow(int n) {
  323.         boolean neg = n < 0;
  324.         if (neg)
  325.             n = -n;
  326.         FP x = this, y = ONE;
  327.         while (n != 0) {
  328.             if ((n & 1) != 0) {
  329.                 y = y.mul(x);
  330.             }
  331.             x = x.square();
  332.             n >>>= 1;
  333.         }
  334.         return neg ? y.inv() : y;
  335.     }
  336.  
  337.     public FP div(FP other) {
  338.         if (other.sign() == 0)
  339.             return MAX.mulSign(this).mulSign(other);
  340.         if (this.sign() == 0)
  341.             return ZERO;
  342.         int sign = (this.sign() ^ other.sign()) | 1;
  343.         int exp = this.exponent() - other.exponent();
  344.         long mant = (this.mantissa() << (1 + BITS)) / other.mantissa();
  345.         if ((mant & (2l << BITS)) != 0) {
  346.             mant >>>= 1;
  347.         } else {
  348.             --exp;
  349.         }
  350.         return new FP(sign, exp, mant);
  351.     }
  352.  
  353.     public FP inv() {
  354.         return ONE.div(this);
  355.     }
  356.  
  357.     public FP sub(FP other) {
  358.         return add(other.neg());
  359.     }
  360.  
  361.     public FP add(FP other) {
  362.         if (sign() == 0)
  363.             return other;
  364.         if (other.sign() == 0)
  365.             return this;
  366.  
  367.         FP small = this;
  368.         FP big = other;
  369.         if (small.exponent() == big.exponent()) {
  370.             if (small.mantissa() > big.mantissa()) {
  371.                 small = other;
  372.                 big = this;
  373.             }
  374.         } else if (small.exponent() > big.exponent()) {
  375.             small = other;
  376.             big = this;
  377.         }
  378.         int exp = big.exponent();
  379.         long mant = big.mantissa();
  380.         long delta = small.mantissa() >>> (big.exponent() - small.exponent());
  381.         if (big.sign() == small.sign()) {
  382.             mant += delta;
  383.             if ((mant & (2l << BITS)) != 0) {
  384.                 mant >>>= 1;
  385.                 ++exp;
  386.             }
  387.         } else {
  388.             mant -= delta;
  389.             if (mant == 0)
  390.                 return ZERO;
  391.             while ((mant & (1l << BITS)) == 0) {
  392.                 mant <<= 1;
  393.                 --exp;
  394.             }
  395.         }
  396.         return new FP(big.sign(), exp, mant);
  397.     }
  398.  
  399.     protected FP add(double v) {
  400.         return add(new FP(v));
  401.     }
  402.  
  403.     static protected FP[] ln = { new FP(8.690628917915396e-06),
  404.             new FP(0.9992996219306662), new FP(-0.4907434587925273),
  405.             new FP(0.2867076984634543), new FP(-0.1332213692732176),
  406.             new FP(0.03110469698575859) };
  407.  
  408.     public FP ln() {
  409.         if (sign() <= 0)
  410.             return MAX.neg();
  411.         FP x = new FP(1, 0, mantissa()).sub(ONE), y = ZERO;
  412.         for (int i = ln.length; --i >= 0;)
  413.             y = y.mul(x).add(ln[i]);
  414.         int exp = this.exponent() < 0 ? -this.exponent() : this.exponent();
  415.         while (exp > 0) {
  416.             y = y.add(LN2);
  417.             --exp;
  418.         }
  419.         if (this.exponent() < 0)
  420.             y = y.neg();
  421.         return y;
  422.     }
  423.  
  424.     public FP log10() {
  425.         return ln().div(LN10);
  426.     }
  427.  
  428.     public FP sqrt() {
  429.         if (sign() <= 0)
  430.             return ZERO;
  431.  
  432.         long op = mantissa() << BITS;
  433.         long one = 1l << (BITS + BITS);
  434.         long res = 0;
  435.         while (one != 0) {
  436.             if (op >= res + one) {
  437.                 op -= res + one;
  438.                 res += one << 1;
  439.             }
  440.             res >>>= 1;
  441.             one >>>= 2;
  442.         }
  443.         /* Do arithmetic rounding to nearest integer */
  444.         if (op > res) {
  445.             res++;
  446.         }
  447.  
  448.         FP x = new FP(1, this.exponent() >> 1, res);
  449.         if ((this.exponent() & 1) != 0)
  450.             x = x.mul(SQRT2);
  451.         return x;
  452.     }
  453.  
  454.     public FP exp() {
  455.         // exp(2^x * y) = exp(y)^(2^x) = exp(2^0) * exp(2^-1)
  456.  
  457.         if (sign() == 0)
  458.             return ONE;
  459.  
  460.         // exp(y)
  461.         FP x = ONE;
  462.         if (false) {
  463.             FP y = E;
  464.             long m = mantissa(), msk = ONE_MSK;
  465.             while (m != 0 && !ONE.equals(y)) {
  466.                 if ((m & msk) != 0) {
  467.                     x = x.mul(y);
  468.                     m ^= msk;
  469.                 }
  470.                 y = y.sqrt();
  471.                 msk >>>= 1;
  472.             }
  473.         } else {
  474.             // optim
  475.             long z = mantissa(), y = ONE_MSK, t, k;
  476.             int exp = 0;
  477.             for (k = 1; (t = (long) (Math.log((k + 1.0) / k) * ONE_MSK + 0.5)) != 0; k <<= 1) {
  478.                 t = z - t;
  479.                 if (t >= 0) {
  480.                     z = t;
  481.                     y += y / k;
  482.                     if ((y & (ONE_MSK * 2)) != 0) {
  483.                         y >>>= 1;
  484.                         ++exp;
  485.                     }
  486.                 }
  487.             }
  488.             x = new FP(1, exp, y);
  489.         }
  490.  
  491.         // exp(2^exponent)
  492.         int exp = exponent();
  493.         while (exp > 0 && !MAX.equals(x)) {
  494.             x = x.square();
  495.             --exp;
  496.         }
  497.         while (exp < 0 && !ONE.equals(x)) {
  498.             x = x.sqrt();
  499.             ++exp;
  500.         }
  501.  
  502.         return sign() < 0 ? x.inv() : x;
  503.     }
  504. }
Advertisement
Add Comment
Please, Sign In to add comment