Java BigDecimal Create bigDecimalFromString(String s)

Here you can find the source of bigDecimalFromString(String s)

Description

big Decimal From String

License

Open Source License

Declaration

public static java.math.BigDecimal bigDecimalFromString(String s) 

Method Source Code

//package com.java2s;
//   Use is governed by the terms of the J/Link license agreement, which can be found at

import java.math.MathContext;

public class Main {
    public static java.math.BigDecimal bigDecimalFromString(String s) {

        // Need to accommodate InputForm bigdecimal, e.g. -1.234567...89e35\0`53.101 or -1.234567...89`53.101*^35\0`53.101.
        // Note that I probably need to respect the precision info that is supplied via the numbermark.
        // The idea is to extract the digits as a big integer and then determine the scale. These
        // are the components we need for the BigDecimal constructor.

        int len = s.length();
        byte[] data = s.getBytes();

        // For some reason the kernel can write real numbers with spaces embedded and only junk afterwards,
        // and when reading reals MLGetString and related funcs will convert spaces into 0 chars (\0, not '0'),
        // so the first step is to truncate the string at the first \0 char (actually, because it is not
        // clear that all versions of the kernel will do this conversion, truncate at either ' ' or \0).
        int i;//from  ww  w  . j ava  2 s.  c om
        int tickPos = -1;
        boolean finishedWithDigits = false;
        for (i = 0; i < len; i++) {
            byte b = data[i];
            if ((b == 0 || b == 32) && !finishedWithDigits) {
                len = i;
                finishedWithDigits = true;
            } else if (b == 96) {
                tickPos = i;
            }
        }

        // Get precision info, if present.
        int precision = -1;
        /* This was an attempt to get precision info from M reals into the BigDecimal objects using new features in
         * Java 5. I think it is working, although other changes are needed to use it correctly (MathLinkImplBase.put(Object),
         * where BigDecimals are written onto a link). There are issues with this idea, and M reals can never be converted
         * into BigDecimal with complete accuracy (for example, M reals can have non-integer precision). I am not 
         * convinced right now that this is the right thing to do, or at least that there wouldn't be unintended consequences
         * or code breakage, so I am leaving it commented out.
        if (tickPos > 0) {
        int startOfPrecision = tickPos + 1;
        int endOfPrecision = startOfPrecision;
        while (endOfPrecision < len && Character.isDigit(data[endOfPrecision]))
        endOfPrecision++;
        // At end of above loop, endOfPrecision points to the first position past the end of precision info. It could
        // be a decimal point, since precision info from M is often non-integer, but we can only handle integer
        // precision. The end could also be because we hit the end of the string, or we hit the *^ chars.
        if (endOfPrecision > startOfPrecision)
        precision = Integer.parseInt(s.substring(startOfPrecision, endOfPrecision));
        }
        */

        byte[] digitBuf = new byte[len];

        int digitCount = 0;
        int decimalPos = -1;
        boolean isNegative = false;

        // First get the digits from the number, ignoring the exponent. Record position of the decimal point.
        for (i = 0; i < len; i++) {
            byte b = data[i];
            if (b >= 48 && b <= 57) {
                // Digit
                digitBuf[digitCount++] = b;
            } else if (b == 45) {
                // Minus sign
                isNegative = true;
                digitBuf[digitCount++] = b;
            } else if (b == 46) {
                decimalPos = i;
            } else {
                // End of digits for unscaled value part of BigDecimal.
                break;
            }
        }
        // Note that the value of i at the end if this loop is used later.

        // Now create in unscaledValue an integer that contains all the digits of the original real, but no decimal point.
        String unscaledValue = new String(digitBuf, 0, digitCount);
        // this scale value will be modified later if there is an exponent.
        int scale = decimalPos != -1 ? digitCount - decimalPos : 0;

        // Advance i to point to first char past either 'e' or '*^'. That position is the start of the exponent.
        for (; i < len; i++) {
            byte b = data[i];
            if (b == 101) {
                // e (old style number format)
                i++;
                break;
            } else if (b == 42) {
                // * (new style number format)
                i += 2;
                break;
            }
        }

        // Now get exponent as an integer. Reuse digitBuf.
        digitCount = 0;
        for (; i < len; i++) {
            byte b = data[i];
            if (b == 45 || (b >= 48 && b <= 57)) {
                // Minus sign or digit.
                digitBuf[digitCount++] = b;
            } else if (b == 43) {
                // Plus sign. Do nothing (Integer.parseInt() cannot handle a leading + sign, if you can believe that).
            } else {
                break;
            }
        }
        if (digitCount > 0) {
            int exponent = Integer.parseInt(new String(digitBuf, 0, digitCount));
            scale -= exponent;
        }

        if (precision >= 0)
            return new java.math.BigDecimal(new java.math.BigInteger(unscaledValue), scale,
                    new MathContext(precision));
        else
            return new java.math.BigDecimal(new java.math.BigInteger(unscaledValue), scale);
    }
}

Related

  1. bigDecimal(Number num)
  2. bigDecimal(Object object)
  3. bigDecimalFromBytes(byte[] decimalBytes, int scale)
  4. bigDecimalValue(final Number number)
  5. bigDecimalValueOf(Number n)
  6. createBigDecimal(double v)
  7. createBigDecimal(final String value)