123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691 |
- <!DOCTYPE html>
- <html lang='en'>
- <head>
- <meta charset='utf-8' />
- <meta name="Author" content="M Mclaughlin">
- <title>Testing BigNumber</title>
- <style>
- body {margin: 0; padding: 0; font-family: Calibri, Arial, Sans-Serif;}
- div {margin: 1em 0;}
- h1, #counter {text-align: center; background-color: rgb(225, 225, 225);
- margin-top: 1em; padding: 0.2em; font-size: 1.2em;}
- a {color: rgb(0, 153, 255); margin: 0 0.6em;}
- .links {position: fixed; bottom: 1em; right: 2em; font-size: 0.8em;}
- .form, #time {width: 36em; margin: 0 auto;}
- .form {text-align: left; margin-top: 1.4em;}
- .random input {margin-left: 1em;}
- .small {font-size: 0.9em;}
- .methods {margin: 1em auto; width: 28em;}
- .iterations input, .left {margin-left: 1.6em;}
- .info span {margin-left: 1.6em; font-size: 0.9em;}
- .info {margin-top: 1.6em;}
- .random input, .iterations input {margin-right: 0.3em;}
- .random label, .iterations label, .bigd label {font-size: 0.9em;
- margin-left: 0.1em;}
- .methods label {width: 5em; margin-left: 0.2em; display: inline-block;}
- .methods label.right {width: 2em;}
- .red {color: red; font-size: 1.1em; font-weight: bold;}
- button {width: 10em; height: 2em;}
- #dp, #r, #digits, #reps {margin-left: 0.8em;}
- #bigint {font-style: italic; display: none;}
- #gwt, #icu4j, #bd, #bigint {margin-left: 1.5em;}
- #division {display: none;}
- #counter {font-size: 2em; background-color: rgb(235, 235, 235);}
- #time {text-align: center;}
- #results {margin: 0 1.4em;}
- </style>
- <script src='../bignumber.js'></script>
- <script src='./lib/bigdecimal_GWT/bigdecimal.js'></script>
- </head>
- <body>
- <h1>Testing BigNumber against BigDecimal</h1>
- <div class='form'>
- <div class='methods'>
- <input type='radio' id=0 name=1/><label for=0>plus</label>
- <input type='radio' id=3 name=1/><label for=3>dividedBy</label>
- <input type='radio' id=6 name=1/><label for=6 class='right'>absoluteValue</label>
- <br>
- <input type='radio' id=1 name=1/><label for=1>minus</label>
- <input type='radio' id=4 name=1/><label for=4>modulo</label>
- <input type='radio' id=7 name=1/><label for=7 class='right'>negated</label>
- <br>
- <input type='radio' id=2 name=1/><label for=2>multipliedBy</label>
- <input type='radio' id=5 name=1/><label for=5>comparedTo</label>
- <input type='radio' id=8 name=1/><label for=8 class='right'>exponentiatedBy</label>
- </div>
- <div class='bigd'>
- <span>BigDecimal:</span>
- <input type='radio' name=2 id='gwt' /><label for='gwt'>GWT</label>
- <input type='radio' name=2 id='icu4j' /><label for='icu4j'>ICU4J</label>
- <span id='bigint'>BigInteger</span>
- <span id='bd'>add</span>
- </div>
- <div class='random'>
- Random number digits:<input type='text' id='digits' size=12 />
- <input type='radio' name=3 id='fix' /><label for='fix'>Fixed</label>
- <input type='radio' name=3 id='max' /><label for='max'>Max</label>
- <input type='checkbox' id='int' /><label for='int'>Integers only</label>
- </div>
- <div id='division'>
- <span>Decimal places:<input type='text' id='dp' size=9 /></span>
- <span class='left'>Rounding:<select id='r'>
- <option>UP</option>
- <option>DOWN</option>
- <option>CEIL</option>
- <option>FLOOR</option>
- <option>HALF_UP</option>
- <option>HALF_DOWN</option>
- <option>HALF_EVEN</option>
- </select></span>
- </div>
- <div class='iterations'>
- Iterations:<input type='text' id='reps' size=11 />
- <input type='checkbox' id='show'/><label for='show'>Show all (no timing)</label>
- </div>
- <div class='info'>
- <button id='start'>Start</button>
- <span>Click a method to stop</span>
- <span>Press space bar to pause/unpause</span>
- </div>
- </div>
- <div id='counter'>0</div>
- <div id='time'></div>
- <div id='results'></div>
- <div class='links'>
- <a href='https://github.com/MikeMcl/bignumber.js' target='_blank'>BigNumber</a>
- <a href='https://github.com/iriscouch/bigdecimal.js' target='_blank'>GWT</a>
- <a href='https://github.com/dtrebbien/BigDecimal.js/tree/' target='_blank'>ICU4J</a>
- </div>
- <script>
- var i, completedReps, targetReps, cycleReps, cycleTime, prevCycleReps, cycleLimit,
- maxDigits, isFixed, isIntOnly, decimalPlaces, rounding, calcTimeout,
- counterTimeout, script, isGWT, BigDecimal_GWT, BigDecimal_ICU4J,
- bdM, bdTotal, bnM, bnTotal,
- bdMs = ['add', 'subtract', 'multiply', 'divide', 'remainder', 'compareTo',
- 'abs', 'negate', 'pow'],
- bnMs = ['plus', 'minus', 'multipliedBy', 'dividedBy', 'modulo', 'comparedTo', 'absoluteValue',
- 'negated', 'exponentiatedBy'],
- lastRounding = 4,
- pause = false,
- up = true,
- timingVisible = false,
- showAll = false,
- // Edit defaults here
- DEFAULT_REPS = 10000,
- DEFAULT_DIGITS = 20,
- DEFAULT_DECIMAL_PLACES = 20,
- DEFAULT_ROUNDING = 4,
- MAX_POWER = 20,
- CHANCE_NEGATIVE = 0.5, // 0 (never) to 1 (always)
- CHANCE_INTEGER = 0.2, // 0 (never) to 1 (always)
- MAX_RANDOM_EXPONENT = 100,
- SPACE_BAR = 32,
- ICU4J_URL = './lib/bigdecimal_ICU4J/BigDecimal-all-last.js',
- //
- $ = function (id) {return document.getElementById(id)},
- $INPUTS = document.getElementsByTagName('input'),
- $BD = $('bd'),
- $BIGINT = $('bigint'),
- $DIGITS = $('digits'),
- $GWT = $('gwt'),
- $ICU4J = $('icu4j'),
- $FIX = $('fix'),
- $MAX = $('max'),
- $INT = $('int'),
- $DIV = $('division'),
- $DP = $('dp'),
- $R = $('r'),
- $REPS = $('reps'),
- $SHOW = $('show'),
- $START = $('start'),
- $COUNTER = $('counter'),
- $TIME = $('time'),
- $RESULTS = $('results'),
- // Get random number in normal notation.
- getRandom = function () {
- var z,
- i = 0,
- // n is the number of digits - 1
- n = isFixed ? maxDigits - 1 : Math.random() * (maxDigits || 1) | 0,
- r = ( Math.random() * 10 | 0 ) + '';
- if (n) {
- if (r == '0')
- r = isIntOnly ? ( ( Math.random() * 9 | 0 ) + 1 ) + '' : (z = r + '.');
- for ( ; i++ < n; r += Math.random() * 10 | 0 ){}
- if (!z && !isIntOnly && Math.random() > CHANCE_INTEGER) {
- r = r.slice( 0, i = (Math.random() * n | 0) + 1 ) +
- '.' + r.slice(i);
- }
- }
- // Avoid division by zero error with division and modulo
- if ((bdM == 'divide' || bdM == 'remainder') && parseFloat(r) === 0)
- r = ( ( Math.random() * 9 | 0 ) + 1 ) + '';
- return Math.random() > CHANCE_NEGATIVE ? r : '-' + r;
- },
- // Get random number in exponential notation (if isIntOnly is false).
- // GWT BigDecimal BigInteger does not accept exponential notation.
- //getRandom = function () {
- // var i = 0,
- // // n is the number of significant digits - 1
- // n = isFixed ? maxDigits - 1 : Math.random() * (maxDigits || 1) | 0,
- // r = ( ( Math.random() * 9 | 0 ) + 1 ) + '';
- //
- // for (; i++ < n; r += Math.random() * 10 | 0 ){}
- //
- // if ( !isIntOnly ) {
- //
- // // Add exponent.
- // r += 'e' + ( Math.random() > 0.5 ? '+' : '-' ) +
- // ( Math.random() * MAX_RANDOM_EXPONENT | 0 );
- // }
- //
- // return Math.random() > CHANCE_NEGATIVE ? r : '-' + r
- //},
- showTimings = function () {
- var i, bdS, bnS,
- sp = '',
- r = bnTotal < bdTotal
- ? (bnTotal ? bdTotal / bnTotal : bdTotal)
- : (bdTotal ? bnTotal / bdTotal : bnTotal);
- bdS = 'BigDecimal: ' + (bdTotal || '<1');
- bnS = 'BigNumber: ' + (bnTotal || '<1');
- for ( i = bdS.length - bnS.length; i-- > 0; sp += ' '){}
- bnS = 'BigNumber: ' + sp + (bnTotal || '<1');
- $TIME.innerHTML =
- 'No mismatches<div>' + bdS + ' ms<br>' + bnS + ' ms</div>' +
- ((r = parseFloat(r.toFixed(1))) > 1
- ? 'Big' + (bnTotal < bdTotal ? 'Number' : 'Decimal')
- + ' was ' + r + ' times faster'
- : 'Times approximately equal');
- },
- clear = function () {
- clearTimeout(calcTimeout);
- clearTimeout(counterTimeout);
- $COUNTER.style.textDecoration = 'none';
- $COUNTER.innerHTML = '0';
- $TIME.innerHTML = $RESULTS.innerHTML = '';
- $START.innerHTML = 'Start';
- },
- begin = function () {
- var i;
- clear();
- targetReps = +$REPS.value;
- if (!(targetReps > 0)) return;
- $START.innerHTML = 'Restart';
- i = +$DIGITS.value;
- $DIGITS.value = maxDigits = i && isFinite(i) ? i : DEFAULT_DIGITS;
- for (i = 0; i < 9; i++) {
- if ($INPUTS[i].checked) {
- bnM = bnMs[$INPUTS[i].id];
- bdM = bdMs[$INPUTS[i].id];
- break;
- }
- }
- if (bdM == 'divide') {
- i = +$DP.value;
- $DP.value = decimalPlaces = isFinite(i) ? i : DEFAULT_DECIMAL_PLACES;
- rounding = +$R.selectedIndex;
- BigNumber.config({ DECIMAL_PLACES: decimalPlaces, ROUNDING_MODE: rounding });
- }
- isFixed = $FIX.checked;
- isIntOnly = $INT.checked;
- showAll = $SHOW.checked;
- BigDecimal = (isGWT = $GWT.checked)
- ? (isIntOnly ? BigInteger : BigDecimal_GWT)
- : BigDecimal_ICU4J;
- prevCycleReps = cycleLimit = completedReps = bdTotal = bnTotal = 0;
- pause = false;
- cycleReps = showAll ? 1 : 0.5;
- cycleTime = +new Date();
- setTimeout(updateCounter, 0);
- },
- updateCounter = function () {
- if (pause) {
- if (!timingVisible && !showAll) {
- showTimings();
- timingVisible = true;
- }
- counterTimeout = setTimeout(updateCounter, 50);
- return;
- }
- $COUNTER.innerHTML = completedReps;
- if (completedReps < targetReps) {
- if (timingVisible) {
- $TIME.innerHTML = '';
- timingVisible = false;
- }
- if (!showAll) {
- // Adjust cycleReps so counter is updated every second-ish
- if (prevCycleReps != cycleReps) {
- // cycleReps too low
- if (+new Date() - cycleTime < 1e3) {
- prevCycleReps = cycleReps;
- if (cycleLimit) {
- cycleReps += ((cycleLimit - cycleReps) / 2);
- } else {
- cycleReps *= 2;
- }
- // cycleReps too high
- } else {
- cycleLimit = cycleReps;
- cycleReps -= ((cycleReps - prevCycleReps) / 2);
- }
- cycleReps = Math.floor(cycleReps) || 1;
- cycleTime = +new Date();
- }
- if (completedReps + cycleReps > targetReps) {
- cycleReps = targetReps - completedReps;
- }
- }
- completedReps += cycleReps;
- calcTimeout = setTimeout(calc, 0);
- // Finished - show timings summary
- } else {
- $START.innerHTML = 'Start';
- $COUNTER.style.textDecoration = 'underline';
- if (!showAll) {
- showTimings();
- }
- }
- },
- calc = function () {
- var start, bdT, bnT, bdR, bnR,
- xs = [cycleReps],
- ys = [cycleReps],
- bdRs = [cycleReps],
- bnRs = [cycleReps];
- // Generate random operands
- for (i = 0; i < cycleReps; i++) {
- xs[i] = getRandom();
- }
- if (bdM == 'pow') {
- for (i = 0; i < cycleReps; i++) {
- ys[i] = Math.floor(Math.random() * (MAX_POWER + 1)) + '';
- }
- // No second operand needed for abs and negate
- } else if (bdM != 'abs' && bdM != 'negate') {
- for (i = 0; i < cycleReps; i++) {
- ys[i] = getRandom();
- }
- }
- //********************************************************************//
- //************************** START TIMING ****************************//
- //********************************************************************//
- // BigDecimal
- if (bdM == 'divide') {
- start = +new Date();
- for (i = 0; i < cycleReps; i++) {
- bdRs[i] = new BigDecimal(xs[i])[bdM](new BigDecimal(ys[i]),
- decimalPlaces, rounding);
- }
- bdT = +new Date() - start;
- // GWT pow argument must be of type number. ICU4J pow argument must be of type BigDecimal
- } else if (bdM == 'pow' && isGWT) {
- start = +new Date();
- for (i = 0; i < cycleReps; i++) {
- bdRs[i] = new BigDecimal(xs[i])[bdM](+ys[i]);
- }
- bdT = +new Date() - start;
- } else if (bdM == 'abs' || bdM == 'negate') {
- start = +new Date();
- for (i = 0; i < cycleReps; i++) {
- bdRs[i] = new BigDecimal(xs[i])[bdM]();
- }
- bdT = +new Date() - start;
- } else {
- start = +new Date();
- for (i = 0; i < cycleReps; i++) {
- bdRs[i] = new BigDecimal(xs[i])[bdM](new BigDecimal(ys[i]));
- }
- bdT = +new Date() - start;
- }
- // BigNumber
- if (bdM == 'pow') {
- start = +new Date();
- for (i = 0; i < cycleReps; i++) {
- bnRs[i] = new BigNumber(xs[i])[bnM](+ys[i]);
- }
- bnT = +new Date() - start;
- } else if (bdM == 'abs' || bdM == 'negate') {
- start = +new Date();
- for (i = 0; i < cycleReps; i++) {
- bnRs[i] = new BigNumber(xs[i])[bnM]();
- }
- bnT = +new Date() - start;
- } else {
- start = +new Date();
- for (i = 0; i < cycleReps; i++) {
- bnRs[i] = new BigNumber(xs[i])[bnM](new BigNumber(ys[i]));
- }
- bnT = +new Date() - start;
- }
- //********************************************************************//
- //**************************** END TIMING ****************************//
- //********************************************************************//
- // Check for mismatches
- for (i = 0; i < cycleReps; i++) {
- bnR = bnRs[i].toString();
- // Remove any trailing zeros from BigDecimal result
- if (isGWT) {
- bdR = bdM == 'compareTo' || isIntOnly
- ? bdRs[i].toString()
- : bdRs[i].stripTrailingZeros().toPlainString();
- } else {
- // No toPlainString() or stripTrailingZeros() in ICU4J
- bdR = bdRs[i].toString();
- if (bdR.indexOf('.') != -1) {
- bdR = bdR.replace(/\.?0+$/, '');
- }
- }
- if (bdR !== bnR) {
- $RESULTS.innerHTML =
- '<span class="red">Breaking on first mismatch:</span>' +
- '<br><br>' +xs[i] + '<br>' + bnM + '<br>' + ys[i] +
- '<br><br>BigDecimal<br>' + bdR + '<br>' + bnR + '<br>BigNumber';
- if (bdM == 'divide') {
- $RESULTS.innerHTML += '<br><br>Decimal places: ' +
- decimalPlaces + '<br>Rounding mode: ' + rounding;
- }
- return;
- } else if (showAll) {
- $RESULTS.innerHTML = xs[i] + '<br>' + bnM + '<br>' + ys[i] +
- '<br><br>BigDecimal<br>' + bdR + '<br>' + bnR + '<br>BigNumber';
- }
- }
- bdTotal += bdT;
- bnTotal += bnT;
- updateCounter();
- };
- // Event handlers
- document.onkeyup = function (evt) {
- evt = evt || window.event;
- if ((evt.keyCode || evt.which) == SPACE_BAR) {
- up = true;
- }
- };
- document.onkeydown = function (evt) {
- evt = evt || window.event;
- if (up && (evt.keyCode || evt.which) == SPACE_BAR) {
- pause = !pause;
- up = false;
- }
- };
- // BigNumber methods' radio buttons' event handlers
- for (i = 0; i < 9; i++) {
- $INPUTS[i].checked = false;
- $INPUTS[i].disabled = false;
- $INPUTS[i].onclick = function () {
- clear();
- lastRounding = $R.options.selectedIndex;
- $DIV.style.display = 'none';
- bnM = bnMs[this.id];
- $BD.innerHTML = bdM = bdMs[this.id];
- };
- }
- $INPUTS[1].onclick = function () {
- clear();
- $R.options.selectedIndex = lastRounding;
- $DIV.style.display = 'block';
- bnM = bnMs[this.id];
- $BD.innerHTML = bdM = bdMs[this.id];
- };
- // Show/hide BigInteger and disable/un-disable division accordingly as BigInteger
- // throws an exception if division gives "no exact representable decimal result"
- $INT.onclick = function () {
- if (this.checked && $GWT.checked) {
- if ($INPUTS[1].checked) {
- $INPUTS[1].checked = false;
- $INPUTS[0].checked = true;
- $BD.innerHTML = bdMs[$INPUTS[0].id];
- $DIV.style.display = 'none';
- }
- $INPUTS[1].disabled = true;
- $BIGINT.style.display = 'inline';
- } else {
- $INPUTS[1].disabled = false;
- $BIGINT.style.display = 'none';
- }
- };
- $ICU4J.onclick = function () {
- $INPUTS[1].disabled = false;
- $BIGINT.style.display = 'none';
- };
- $GWT.onclick = function () {
- if ($INT.checked) {
- if ($INPUTS[1].checked) {
- $INPUTS[1].checked = false;
- $INPUTS[0].checked = true;
- $BD.innerHTML = bdMs[$INPUTS[0].id];
- $DIV.style.display = 'none';
- }
- $INPUTS[1].disabled = true;
- $BIGINT.style.display = 'inline';
- }
- };
- BigNumber.config({
- DECIMAL_PLACES : 20,
- ROUNDING_MODE : 4,
- EXPONENTIAL_AT: 1E9,
- RANGE: 1E9,
- MODULO_MODE: 1,
- POW_PRECISION: 10000
- });
- // Set defaults
- $MAX.checked = $INPUTS[0].checked = $GWT.checked = true;
- $SHOW.checked = $INT.checked = false;
- $REPS.value = DEFAULT_REPS;
- $DIGITS.value = DEFAULT_DIGITS;
- $DP.value = DEFAULT_DECIMAL_PLACES;
- $R.option = DEFAULT_ROUNDING;
- BigDecimal_GWT = BigDecimal;
- BigDecimal = undefined;
- // Load ICU4J BigDecimal
- script = document.createElement("script");
- script.src = ICU4J_URL;
- script.onload = script.onreadystatechange = function () {
- if (!script.readyState || /loaded|complete/.test(script.readyState)) {
- script = null;
- BigDecimal_ICU4J = BigDecimal;
- $START.onmousedown = begin;
- }
- };
- document.getElementsByTagName("head")[0].appendChild(script);
- /*
- NOTES:
- ICU4J
- =====
- IBM java package: com.ibm.icu.math
- pow's argument must be a BigDecimal.
- Among other differences, doesn't have .toPlainString() or .stripTrailingZeros().
- Exports BigDecimal only.
- Much faster than gwt on Firefox, on Chrome it varies with the method.
- GWT
- ===
- Java standard class library: java.math.BigDecimal
- Exports:
- RoundingMode
- MathContext
- BigDecimal
- BigInteger
- BigDecimal properties:
- ROUND_CEILING
- ROUND_DOWN
- ROUND_FLOOR
- ROUND_HALF_DOWN
- ROUND_HALF_EVEN
- ROUND_HALF_UP
- ROUND_UNNECESSARY
- ROUND_UP
- __init__
- valueOf
- log
- logObj
- ONE
- TEN
- ZERO
- BigDecimal instance properties/methods:
- ( for (var i in new BigDecimal('1').__gwt_instance.__gwtex_wrap) {...} )
- byteValueExact
- compareTo
- doubleValue
- equals
- floatValue
- hashCode
- intValue
- intValueExact
- max
- min
- movePointLeft
- movePointRight
- precision
- round
- scale
- scaleByPowerOfTen
- shortValueExact
- signum
- stripTrailingZeros
- toBigInteger
- toBigIntegerExact
- toEngineeringString
- toPlainString
- toString
- ulp
- unscaledValue
- longValue
- longValueExact
- abs
- add
- divide
- divideToIntegralValue
- multiply
- negate
- plus
- pow
- remainder
- setScale
- subtract
- divideAndRemainder
- */
- </script>
- </body>
- </html>
|