From 6ed7659b4d911cbad9107b563cccb6cf607b055e Mon Sep 17 00:00:00 2001 From: gnosygnu Date: Thu, 27 Aug 2020 06:04:17 -0400 Subject: [PATCH] Core: Parse decimal 'e' as 'E' [#565] --- 100_core/src/gplx/Decimal_adp_.java | 128 +++++++++++--------- 100_core/src/gplx/Decimal_adp__tst.java | 149 ++++++++++++------------ 2 files changed, 149 insertions(+), 128 deletions(-) diff --git a/100_core/src/gplx/Decimal_adp_.java b/100_core/src/gplx/Decimal_adp_.java index e9dd872a5..a03cba250 100644 --- a/100_core/src/gplx/Decimal_adp_.java +++ b/100_core/src/gplx/Decimal_adp_.java @@ -1,6 +1,6 @@ /* XOWA: the XOWA Offline Wiki Application -Copyright (C) 2012-2017 gnosygnu@gmail.com +Copyright (C) 2012-2020 gnosygnu@gmail.com XOWA is licensed under the terms of the General Public License (GPL) Version 3, or alternatively under the terms of the Apache License Version 2.0. @@ -13,57 +13,75 @@ The terms of each license can be found in the source code repository: GPLv3 License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-GPLv3.txt Apache License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-APACHE2.txt */ -package gplx; -import java.math.BigDecimal; import java.math.MathContext; import java.math.RoundingMode; import java.text.DecimalFormat; -import java.text.NumberFormat; -import java.text.ParseException; -import java.util.Locale; -public class Decimal_adp_ { - public static final String Cls_val_name = "decimal"; - public static final Class Cls_ref_type = Decimal_adp.class; - public static Decimal_adp as_(Object obj) {return obj instanceof Decimal_adp ? (Decimal_adp)obj : null;} - public static final Decimal_adp Zero = new Decimal_adp(0); - public static final Decimal_adp One = new Decimal_adp(1); - public static final Decimal_adp Neg1 = new Decimal_adp(-1); - public static final Decimal_adp Const_e = Decimal_adp_.double_(Math_.E); - public static final Decimal_adp Const_pi = Decimal_adp_.double_(Math_.Pi); - public static Decimal_adp base1000_(long v) {return divide_(v, 1000);} - public static Decimal_adp parts_1000_(long num, int frc) {return divide_((num * (1000)) + frc, 1000);} - public static Decimal_adp parts_(long num, int frc) { - // int log10 = frc == 0 ? 0 : (Math_.Log10(frc) + 1); - // int pow10 = (int)Math_.Pow(10, log10); - int pow10 = XtoPow10(frc); - return divide_((num * (pow10)) + frc, pow10); - } - public static Decimal_adp cast(Object obj) {return (Decimal_adp)obj;} - static int XtoPow10(int v) { - if (v > -1 && v < 10) return 10; - else if (v > 9 && v < 100) return 100; - else if (v > 99 && v < 1000) return 1000; - else if (v > 999 && v < 10000) return 10000; - else if (v > 9999 && v < 100000) return 100000; - else if (v > 99999 && v < 1000000) return 1000000; - else if (v > 999999 && v < 10000000) return 10000000; - else if (v > 9999999 && v < 100000000) return 100000000; - else if (v > 99999999 && v < 1000000000) return 1000000000; - else throw Err_.new_wo_type("value must be between 0 and 1 billion", "v", v); - } - public static String CalcPctStr(long dividend, long divisor, String fmt) { - if (divisor == 0) return "%ERR"; - return Decimal_adp_.float_(Float_.Div(dividend, divisor) * 100).To_str(fmt) + "%"; - } - public static Decimal_adp divide_safe_(long lhs, long rhs) {return rhs == 0 ? Zero : divide_(lhs, rhs);} - public static Decimal_adp divide_(long lhs, long rhs) { return new Decimal_adp(new BigDecimal(lhs).divide(new BigDecimal(rhs), Gplx_rounding_context)); } public static Decimal_adp int_(int v) {return new Decimal_adp(new BigDecimal(v));} public static Decimal_adp long_(long v) {return new Decimal_adp(new BigDecimal(v));} - public static Decimal_adp float_(float v) {return new Decimal_adp(new BigDecimal(v));} public static Decimal_adp double_(double v) {return new Decimal_adp(new BigDecimal(v));} - public static Decimal_adp double_thru_str_(double v) {return new Decimal_adp(BigDecimal.valueOf(v));} - public static Decimal_adp db_(Object v) {return new Decimal_adp((BigDecimal)v);} public static Decimal_adp parse(String raw) { - try { - DecimalFormat nf = (DecimalFormat)NumberFormat.getInstance(Locale.US); // always parse as US format; EX:".9" should not be ",9" in german; DATE:2016-01-31 - nf.setParseBigDecimal(true); - BigDecimal bd = (BigDecimal)nf.parse(raw); - return new Decimal_adp(bd); - } catch (ParseException e) { - throw Err_.new_("Decimal_adp_", "parse to decimal failed", "raw", raw); - } - } public static Decimal_adp pow_10_(int v) {return new Decimal_adp(new BigDecimal(1).scaleByPowerOfTen(v));} - public static final MathContext RoundDownContext = new MathContext(0, RoundingMode.DOWN); public static final MathContext Gplx_rounding_context = new MathContext(14, RoundingMode.HALF_UP); // changed from 28 to 14; DATE:2015-07-31 } +package gplx; + +import java.math.BigDecimal; +import java.math.MathContext; +import java.math.RoundingMode; +import java.text.DecimalFormat; +import java.text.NumberFormat; +import java.text.ParseException; +import java.util.Locale; + +public class Decimal_adp_ { + public static final String Cls_val_name = "decimal"; + public static final Class Cls_ref_type = Decimal_adp.class; + public static Decimal_adp as_(Object obj) {return obj instanceof Decimal_adp ? (Decimal_adp)obj : null;} + public static final Decimal_adp Zero = new Decimal_adp(0); + public static final Decimal_adp One = new Decimal_adp(1); + public static final Decimal_adp Neg1 = new Decimal_adp(-1); + public static final Decimal_adp Const_e = Decimal_adp_.double_(Math_.E); + public static final Decimal_adp Const_pi = Decimal_adp_.double_(Math_.Pi); + public static Decimal_adp base1000_(long v) {return divide_(v, 1000);} + public static Decimal_adp parts_1000_(long num, int frc) {return divide_((num * (1000)) + frc, 1000);} + public static Decimal_adp parts_(long num, int frc) { + // int log10 = frc == 0 ? 0 : (Math_.Log10(frc) + 1); + // int pow10 = (int)Math_.Pow(10, log10); + int pow10 = XtoPow10(frc); + return divide_((num * (pow10)) + frc, pow10); + } + public static Decimal_adp cast(Object obj) {return (Decimal_adp)obj;} + static int XtoPow10(int v) { + if (v > -1 && v < 10) return 10; + else if (v > 9 && v < 100) return 100; + else if (v > 99 && v < 1000) return 1000; + else if (v > 999 && v < 10000) return 10000; + else if (v > 9999 && v < 100000) return 100000; + else if (v > 99999 && v < 1000000) return 1000000; + else if (v > 999999 && v < 10000000) return 10000000; + else if (v > 9999999 && v < 100000000) return 100000000; + else if (v > 99999999 && v < 1000000000) return 1000000000; + else throw Err_.new_wo_type("value must be between 0 and 1 billion", "v", v); + } + public static String CalcPctStr(long dividend, long divisor, String fmt) { + if (divisor == 0) return "%ERR"; + return Decimal_adp_.float_(Float_.Div(dividend, divisor) * 100).To_str(fmt) + "%"; + } + public static Decimal_adp divide_safe_(long lhs, long rhs) {return rhs == 0 ? Zero : divide_(lhs, rhs);} + public static Decimal_adp divide_(long lhs, long rhs) { + return new Decimal_adp(new BigDecimal(lhs).divide(new BigDecimal(rhs), Gplx_rounding_context)); + } + public static Decimal_adp int_(int v) {return new Decimal_adp(new BigDecimal(v));} + public static Decimal_adp long_(long v) {return new Decimal_adp(new BigDecimal(v));} + public static Decimal_adp float_(float v) {return new Decimal_adp(new BigDecimal(v));} + public static Decimal_adp double_(double v) {return new Decimal_adp(new BigDecimal(v));} + public static Decimal_adp double_thru_str_(double v) {return new Decimal_adp(BigDecimal.valueOf(v));} + public static Decimal_adp db_(Object v) {return new Decimal_adp((BigDecimal)v);} + public static Decimal_adp parse(String raw) { + try { + DecimalFormat nf = (DecimalFormat)NumberFormat.getInstance(Locale.US); // always parse as US format; EX:".9" should not be ",9" in german; DATE:2016-01-31 + nf.setParseBigDecimal(true); + // 2020-08-27|ISSUE#:565|Parse 'e' as 'E'; PAGE:en.w:Huntington_Plaza + if (raw.contains("e")) { + raw = raw.replace("e", "E"); + } + BigDecimal bd = (BigDecimal)nf.parse(raw); + return new Decimal_adp(bd); + } catch (ParseException e) { + throw Err_.new_("Decimal_adp_", "parse to decimal failed", "raw", raw); + } + } + public static Decimal_adp pow_10_(int v) {return new Decimal_adp(new BigDecimal(1).scaleByPowerOfTen(v));} + public static final MathContext RoundDownContext = new MathContext(0, RoundingMode.DOWN); + public static final MathContext Gplx_rounding_context = new MathContext(14, RoundingMode.HALF_UP); // changed from 28 to 14; DATE:2015-07-31 + } diff --git a/100_core/src/gplx/Decimal_adp__tst.java b/100_core/src/gplx/Decimal_adp__tst.java index e45393b38..d37f4a309 100644 --- a/100_core/src/gplx/Decimal_adp__tst.java +++ b/100_core/src/gplx/Decimal_adp__tst.java @@ -1,6 +1,6 @@ /* XOWA: the XOWA Offline Wiki Application -Copyright (C) 2012-2017 gnosygnu@gmail.com +Copyright (C) 2012-2020 gnosygnu@gmail.com XOWA is licensed under the terms of the General Public License (GPL) Version 3, or alternatively under the terms of the Apache License Version 2.0. @@ -13,75 +13,78 @@ The terms of each license can be found in the source code repository: GPLv3 License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-GPLv3.txt Apache License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-APACHE2.txt */ -package gplx; -import org.junit.*; -public class Decimal_adp__tst { - private final Decimal_adp__fxt fxt = new Decimal_adp__fxt(); - @Test public void divide_() { - fxt.Test_divide(1, 1000, "0.001"); - fxt.Test_divide(1, 3, "0.33333333333333"); - fxt.Test_divide(1, 7, "0.14285714285714"); - } - @Test public void base1000_() { - fxt.Test_base_1000(1000, "1"); - fxt.Test_base_1000(1234, "1.234"); - fxt.Test_base_1000(123, "0.123"); - } - @Test public void parts_() { - fxt.Test_parts(1, 0, "1"); - fxt.Test_parts(1, 2, "1.2"); - fxt.Test_parts(1, 23, "1.23"); - fxt.Test_parts(123, 4567, "123.4567"); - } - @Test public void parse() { - fxt.Test_parse("1", "1"); - fxt.Test_parse("1.2", "1.2"); - fxt.Test_parse("0.1", "0.1"); - fxt.Test_parse("1.2E1", "12"); - } - @Test public void Truncate_decimal() { - fxt.Test_truncate_decimal("1", "1"); - fxt.Test_truncate_decimal("1.1", "1"); - fxt.Test_truncate_decimal("1.9", "1"); - } - @Test public void Fraction1000() { - fxt.Test_frac_1000(1, 1000, 1); // 0.001 - fxt.Test_frac_1000(1, 3, 333); // 0.33333333 - fxt.Test_frac_1000(1234, 1000, 234); // 1.234 - fxt.Test_frac_1000(12345, 10000, 234); // 1.2345 - } - @Test public void Lt() { - fxt.Test_comp_lt(1,123, 2, true); - fxt.Test_comp_lt(1,99999999, 2, true); - } - @Test public void To_str_fmt() { - fxt.Test_to_str_fmt(1, 2, "0.0", "0.5"); - fxt.Test_to_str_fmt(1, 3, "0.0", "0.3"); - fxt.Test_to_str_fmt(10000, 7, "0,000.000", "1,428.571"); - fxt.Test_to_str_fmt(1, 2, "00.00", "00.50"); - } - @Test public void Round() { - fxt.Test_round("123.456", 3, "123.456"); - fxt.Test_round("123.456", 2, "123.46"); - fxt.Test_round("123.456", 1, "123.5"); - fxt.Test_round("123.456", 0, "123"); - fxt.Test_round("123.456", -1, "120"); - fxt.Test_round("123.456", -2, "100"); - fxt.Test_round("123.456", -3, "0"); - - fxt.Test_round("6", -1, "10"); - fxt.Test_round("5", -1, "10"); - fxt.Test_round("6", -2, "0"); - } -} -class Decimal_adp__fxt { - public void Test_divide(int lhs, int rhs, String expd) {Tfds.Eq(expd, Decimal_adp_.divide_(lhs, rhs).To_str());} - public void Test_base_1000(int val, String expd) {Tfds.Eq(expd, Decimal_adp_.base1000_(val).To_str());} - public void Test_parts(int num, int fracs, String expd) {Tfds.Eq(expd, Decimal_adp_.parts_(num, fracs).To_str());} - public void Test_parse(String raw, String expd) {Tfds.Eq(expd, Decimal_adp_.parse(raw).To_str());} - public void Test_truncate_decimal(String raw, String expd) {Tfds.Eq(Decimal_adp_.parse(expd).To_str(), Decimal_adp_.parse(raw).Truncate().To_str());} - public void Test_frac_1000(int lhs, int rhs, int expd) {Tfds.Eq(expd, Decimal_adp_.divide_(lhs, rhs).Frac_1000());} - public void Test_comp_lt(int lhsNum, int lhsFrc, int rhs, boolean expd) {Tfds.Eq(expd, Decimal_adp_.parts_(lhsNum, lhsFrc).Comp_lt(rhs));} - public void Test_to_str_fmt(int l, int r, String fmt, String expd) {Tfds.Eq(expd, Decimal_adp_.divide_(l, r).To_str(fmt));} - public void Test_round(String raw, int places, String expd) {Tfds.Eq_str(expd, Decimal_adp_.parse(raw).Round(places).To_str(), "round");} -} +package gplx; + +import org.junit.*; + +public class Decimal_adp__tst { + private final Decimal_adp__fxt fxt = new Decimal_adp__fxt(); + @Test public void divide_() { + fxt.Test_divide(1, 1000, "0.001"); + fxt.Test_divide(1, 3, "0.33333333333333"); + fxt.Test_divide(1, 7, "0.14285714285714"); + } + @Test public void base1000_() { + fxt.Test_base_1000(1000, "1"); + fxt.Test_base_1000(1234, "1.234"); + fxt.Test_base_1000(123, "0.123"); + } + @Test public void parts_() { + fxt.Test_parts(1, 0, "1"); + fxt.Test_parts(1, 2, "1.2"); + fxt.Test_parts(1, 23, "1.23"); + fxt.Test_parts(123, 4567, "123.4567"); + } + @Test public void parse() { + fxt.Test_parse("1", "1"); + fxt.Test_parse("1.2", "1.2"); + fxt.Test_parse("0.1", "0.1"); + fxt.Test_parse("1.2E1", "12"); + fxt.Test_parse("1.2e1", "12"); // 2020-08-27|ISSUE#:565|Parse 'e' as 'E'; PAGE:en.w:Huntington_Plaza + } + @Test public void Truncate_decimal() { + fxt.Test_truncate_decimal("1", "1"); + fxt.Test_truncate_decimal("1.1", "1"); + fxt.Test_truncate_decimal("1.9", "1"); + } + @Test public void Fraction1000() { + fxt.Test_frac_1000(1, 1000, 1); // 0.001 + fxt.Test_frac_1000(1, 3, 333); // 0.33333333 + fxt.Test_frac_1000(1234, 1000, 234); // 1.234 + fxt.Test_frac_1000(12345, 10000, 234); // 1.2345 + } + @Test public void Lt() { + fxt.Test_comp_lt(1,123, 2, true); + fxt.Test_comp_lt(1,99999999, 2, true); + } + @Test public void To_str_fmt() { + fxt.Test_to_str_fmt(1, 2, "0.0", "0.5"); + fxt.Test_to_str_fmt(1, 3, "0.0", "0.3"); + fxt.Test_to_str_fmt(10000, 7, "0,000.000", "1,428.571"); + fxt.Test_to_str_fmt(1, 2, "00.00", "00.50"); + } + @Test public void Round() { + fxt.Test_round("123.456", 3, "123.456"); + fxt.Test_round("123.456", 2, "123.46"); + fxt.Test_round("123.456", 1, "123.5"); + fxt.Test_round("123.456", 0, "123"); + fxt.Test_round("123.456", -1, "120"); + fxt.Test_round("123.456", -2, "100"); + fxt.Test_round("123.456", -3, "0"); + + fxt.Test_round("6", -1, "10"); + fxt.Test_round("5", -1, "10"); + fxt.Test_round("6", -2, "0"); + } +} +class Decimal_adp__fxt { + public void Test_divide(int lhs, int rhs, String expd) {Tfds.Eq(expd, Decimal_adp_.divide_(lhs, rhs).To_str());} + public void Test_base_1000(int val, String expd) {Tfds.Eq(expd, Decimal_adp_.base1000_(val).To_str());} + public void Test_parts(int num, int fracs, String expd) {Tfds.Eq(expd, Decimal_adp_.parts_(num, fracs).To_str());} + public void Test_parse(String raw, String expd) {Tfds.Eq(expd, Decimal_adp_.parse(raw).To_str());} + public void Test_truncate_decimal(String raw, String expd) {Tfds.Eq(Decimal_adp_.parse(expd).To_str(), Decimal_adp_.parse(raw).Truncate().To_str());} + public void Test_frac_1000(int lhs, int rhs, int expd) {Tfds.Eq(expd, Decimal_adp_.divide_(lhs, rhs).Frac_1000());} + public void Test_comp_lt(int lhsNum, int lhsFrc, int rhs, boolean expd) {Tfds.Eq(expd, Decimal_adp_.parts_(lhsNum, lhsFrc).Comp_lt(rhs));} + public void Test_to_str_fmt(int l, int r, String fmt, String expd) {Tfds.Eq(expd, Decimal_adp_.divide_(l, r).To_str(fmt));} + public void Test_round(String raw, int places, String expd) {Tfds.Eq_str(expd, Decimal_adp_.parse(raw).Round(places).To_str(), "round");} +}