1
0
mirror of https://github.com/MikeMcl/decimal.js.git synced 2024-10-27 20:34:12 +00:00
This commit is contained in:
Michael Mclaughlin 2014-06-04 23:59:07 +01:00
parent 7524fbaefe
commit e02587a173
8 changed files with 1321 additions and 1054 deletions

View File

@ -9,7 +9,7 @@ An arbitrary-precision Decimal type for JavaScript.
- Simple API but full-featured
- Replicates the `toExponential`, `toFixed`, `toPrecision` and `toString` methods of JavaScript's Number type
- Includes a `toFraction` and correctly-rounded `exp`, `ln`, `log` and `sqrt` functions
- Supports non-integer powers (although performance is limited)
- Supports non-integer powers
- Works with numbers with or without fraction digits in bases from 2 to 64 inclusive
- Stores values in an accessible decimal floating-point format
- No dependencies
@ -136,11 +136,11 @@ Many of the methods of JavaScript's Math object are also replicated
Decimal.sqrt('6.98372465832e+9823') // '8.3568682281821340204e+4911'
Decimal.pow(2, 0.0979843) // '1.0702770511687781839'
The value of a Decimal is stored in a decimal floating point format in terms of a coefficient, exponent and sign.
The value of a Decimal is stored in a floating point format in terms of a coefficient, exponent and sign.
x = new Decimal(-123.456);
x.c // '1,2,3,4,5,6' coefficient (i.e. significand)
x.e // 2 exponent
x = new Decimal(-12345.67);
x.c // [ 12345, 6700000 ] coefficient (base 10000)
x.e // 4 exponent (base 10)
x.s // -1 sign
For further information see the [API](http://mikemcl.github.io/decimal.js/) reference in the *doc* directory.
@ -198,6 +198,9 @@ See LICENCE.
## Change Log
####3.0.0
* 4/06/2014 `random` simplified. Major internal changes mean the properties of a Decimal must now be considered read-only.
####2.1.0
* 4/06/2014 Amend UMD

1920
decimal.js

File diff suppressed because it is too large Load Diff

4
decimal.min.js vendored

File diff suppressed because one or more lines are too long

View File

@ -492,31 +492,17 @@ x.equals(y) // true</pre>
<h5 id="Drand">
random<code class='inset'>.random([limit [, sd]]) <i>&rArr; Decimal</i></code>
random<code class='inset'>.random([dp]) <i>&rArr; Decimal</i></code>
</h5>
<p><code>dp</code>: <i>number</i>: integer, 0 to 1e+9 inclusive</p>
<p>
<code>limit</code>: <i>number|string|Decimal</i><br /> Default value: <code>1</code><br />
<code>sd</code>: <i>number</i>: integer, 1 to 1e+9 inclusive<br />
<i>See <code><a href="#decimal">Decimal</a></code> for further parameter details.</i>
Returns a new Decimal with a pseudo-random value equal to or greater than <code>0</code> and
less than <code>1</code>.
</p>
<p>
Returns a new Decimal with a pseudo-random value equal to or greater in magnitude than
<code>0</code> and lower in magnitude than <code>limit</code>, and with the same sign as
<code>limit</code>.
</p>
<p>
If <code>limit</code> is omitted then it will be <code>1</code> and the return value will
have <a href='#precision'><code>precision</code></a> significant digits (or less if there are
trailing zeros produced).
</p>
<p>
If <code>limit</code> is included and <code>sd</code> is omitted then the return value
will be an integer. If <code>sd</code> is included, the return value will have
<code>sd</code> significant digits (or less if there are trailing zeros produced).
</p>
<p>
If <code>limit</code> is a high value be sure to include a precision, otherwise this method
may be slow to return because all integer digits will be generated.
The return value will have <code>dp</code></a> decimal places (or less if trailing zeros are
produced). If <code>dp</code> is omitted then the number of decimal places will
default to the current <a href='#precision'><code>precision</code></a> setting.
</p>
<p>
Depending on the value of a Decimal constructor's <a href='#crypto'><code>crypto</code></a>
@ -530,33 +516,11 @@ x.equals(y) // true</pre>
<code>crypto</code> methods is to be used, the value of a returned Decimal should be
cryptographically-secure and statistically indistinguishable from a random value.
</p>
<pre>// A value in the range [0, 1) with precision significant digits
Decimal.config({ precision: 10 })
<pre>Decimal.config({ precision: 10 })
Decimal.random() // '0.4117936847'
// A value in the range [0, 1) with 20 significant digits
Decimal.random(1, 20) // '0.48193327636914089007'
Decimal.random(20) // '0.78193327636914089009'</pre>
// An integer in the range [0, 1)
Decimal.random(1) // '0' (always zero)
// An integer in the range [0, 10)
Decimal.random(10) // '6'
// An integer in the range (-100, 0]
Decimal.random(-100) // '-82'
// An integer in the range [0, 9e9999999999)
Decimal.random('9e99999999999') // A browser will hang
// A value in the range [0, 9e9999999999) with 10 significant digits
Decimal.random('9e99999999999', 25) // '1.508652055e+99999999999'
// A value in the range (-0.0125, 0] with 16 significant digits
Decimal.random(-0.0125, 16) // '-0.0001963482803540358'
// A value in the range [0, 0.9) with 1 significant digit
Decimal.random(0.9, 1) // '0.2'</pre>
@ -869,7 +833,12 @@ Decimal.modulo // 9</pre>
</p>
<p>
If neither function is supported by the host environment or if <code>crypto</code> is falsey
then the source of randomness will be <code>Math.random</code>.
then the source of randomness will be <code>Math.random</code>. If the <code>crypto</code>
property is set directly (i.e. without using <code>config</code>) to <code>true</code>, then
at the time the <code>random</code> method is called, if
<a href='#errors'><code>errors</code></a> is <code>true</code>, an error will be thrown if the
<code>crypto</code> methods are unavailable.
</p>
</p>
<pre>
Decimal.crypto // false
@ -1746,9 +1715,9 @@ JSON.parse(str, function (key, val) {
would be serialized, rather then the string returned by <code>valueOf</code>:</p>
<pre>JSON.stringify( [x, y, z] )
/*
"[{"s":1,"e":459,"c":[1,7,7,7]},
{"s":1,"e":2,"c":[2,3,5,4,3,2,5]},
{"s":1,"e":-3,"c":[9,8,0,7,4]}]"
"[{"s":1,"e":459,"c":[17770]},
{"s":1,"e":2,"c":[235,4325000]},
{"s":1,"e":-3,"c":[98074]}]"
*/</pre>
@ -1823,8 +1792,7 @@ z = new Decimal(-0)
</p>
<p>
The performance of this method degrades exponentially with increasing digits. For
non-integer exponents in particular, even when only quite a small number of significant
digits is required, the performance of this method may not be adequate.
non-integer exponents in particular, the performance of this method may not be adequate.
</p>
<pre>
Math.pow(0.7, 2) // 0.48999999999999994
@ -2038,7 +2006,7 @@ x.valueOf() // '1.777e+457'</pre>
<td class='centre' id='coefficient'><b>c</b></td>
<td>coefficient<sup>*</sup></td>
<td><i>number</i><code style='color:#000'>[]</code></td>
<td> Array of single digits</td>
<td> Array of integers, each 0 - 1e7</td>
</tr>
<tr>
<td class='centre' id='exponent'><b>e</b></td>
@ -2058,19 +2026,23 @@ x.valueOf() // '1.777e+457'</pre>
The value of any of the three properties may also be <code>null</code>.
</p>
<p>
The value of a Decimal is stored in a normalised decimal floating point
format which corresponds to the value's <code><a href='#toE'>toExponential</a></code> form,
with the decimal point to be positioned after the most significant
(left-most) digit of the coefficient.
The properties are best considered to be read-only.
</p>
<p>
Note that, as with JavaScript numbers, the original exponent and
fractional trailing zeros are not preserved.
From version 3 of this library, the value of a Decimal is stored in a normalised base
<code>10000</code> floating point format. While previously it was acceptable to change the
exponent of a Decimal by writing to its exponent property directly, this is no longer
recommended (as the number of digits in the first element of the coefficient array is
dependent on the exponent, so the coefficient would also need to be altered).
</p>
<p>
As with JavaScript numbers, the original exponent and fractional trailing zeros of a number
are not preserved.
</p>
<pre>
x = new Decimal(0.123) // '0.123'
x.toExponential() // '1.23e-1'
x.c // '1,2,3'
x.c // [ 1230000 ]
x.e // -1
x.s // 1
@ -2078,31 +2050,11 @@ y = new Number(-123.4567000e+2) // '-12345.67'
y.toExponential() // '-1.234567e+4'
z = new Decimal('-123.4567000e+2') // '-12345.67'
z.toExponential() // '-1.234567e+4'
z.c // '1,2,3,4,5,6,7'
z.c // [ 12345, 6700000 ]
z.e // 4
z.s // -1</pre>
<p>
A Decimal is mutable in the sense that the value of its properties can
be changed.<br />
For example, to rapidly shift a value by a power of 10:
</p>
<pre>
x = new Decimal('1234.000') // '1234'
x.toExponential() // '1.234e+3'
x.c // '1,2,3,4'
x.e // 3
x.e = -5
x // '0.00001234'</pre>
<p>
If changing the coefficient array directly, which is not recommended, be
careful to avoid leading or trailing zeros (unless zero itself is being
represented).
</p>
<h4 id="zero-nan-infinity">Zero, NaN and Infinity</h4>
<p>
@ -2276,6 +2228,11 @@ y.s // -1</pre>
<td>argument not a boolean or binary digit</td>
<td>Ignore</td>
</tr>
<tr>
<td><code>random</code></td>
<td><code>crypto</code> unavailable</td>
<td>Use <code>Math.random</code></td>
</tr>
<tr>
<td rowspan=4>
<code>

View File

@ -1,7 +1,7 @@
{
"name": "decimal.js",
"description": "An arbitrary-precision Decimal type for JavaScript.",
"version": "2.1.0",
"version": "3.0.0",
"keywords": [
"arbitrary",
"precision",
@ -31,6 +31,6 @@
"license": "MIT",
"scripts": {
"test": "node ./test/every-test.js",
"build": "uglifyjs decimal.js -c -m -o decimal.min.js --preamble '/* decimal.js v2.1.0 https://github.com/MikeMcl/decimal.js/LICENCE */'"
"build": "uglifyjs decimal.js -c -m -o decimal.min.js --preamble '/* decimal.js v3.0.0 https://github.com/MikeMcl/decimal.js/LICENCE */'"
}
}

View File

@ -45,7 +45,6 @@
<!-- <script src='../toSD.js'></script> -->
<!-- <script src='../toStringEtc.js'></script> -->
<!-- <script src='../trunc.js'></script> -->
</body>
</html>

View File

@ -1,6 +1,6 @@
var count = (function random(Decimal) {
var start = +new Date(),
error, i, j, limit, log, pr, u,
dp, error, i, j, k, log, m, r,
passed = 0,
total = 0;
@ -14,20 +14,7 @@ var count = (function random(Decimal) {
}
if (!Decimal && typeof require === 'function') {
Decimal = require('../decimal');
}
function assert(result, r, message) {
total++;
if (result === true) {
passed++;
//log('\n r: ' + r);
} else {
error('\n Test number: ' + total + ' failed');
error(' r: ' + r);
error(' ' + message);
//process.exit();
}
Decimal = require('../decimal.js');
}
function assertException(func, message) {
@ -49,74 +36,65 @@ var count = (function random(Decimal) {
}
}
function T(limit, pr){
var i, r, d;
if ( !limit ) {
limit = new Decimal(1);
pr = Decimal.precision;
}
for ( i = 0; i < 17; i++ ) {
r = Decimal.random(limit, pr);
//log(r.toString());
d = r.c.length;
if ( pr == null ) {
d = Math.max(d, r.e + 1) - r.e - 1;
assert(d === 0, r, 'dp is not 0: ' + d);
} else {
assert(d <= pr, r, 'sd: ' + d + ' > pr: ' + pr);
}
assert(r.gte(0), r, 'r < 0');
assert(r.lt(limit), r, 'r >= limit: ' + limit);
}
}
log('\n Testing random...');
// First iteration crypto: false, second iteration crypto: true.
Decimal.config({ crypto: false, errors: true });
Decimal.config({ errors: true, crypto: false });
for ( i = 0; i < 2; i++ ) {
//log( '\n crypto: ' + Decimal.crypto );
for ( i = 0; i < 9996; i++ ) {
Decimal.precision = Math.random() * 100 + 1 | 0;
//log( Decimal.precision );
//Decimal.crypto = false;
//Decimal.crypto = true;
// 50% chance that Decimal.crypto is true.
//Decimal.crypto = Math.random() > 0.5;
for ( j = 0; j < 10; j++ ) {
T();
T(u);
T(null);
T(1);
T(1, u);
T(1, null);
T(10);
T(1000);
// limit will have 1 - 17 integer digits and 1 - 17 fraction digits.
limit = +(Math.random() + '').slice(2, Math.random() * 17 + 3 | 0) +
(Math.random() + '').slice(1, Math.random() * 17 + 3 | 0);
if ( +limit == 0 ) {
limit = 1;
if ( Math.random() > 0.5 ) {
dp = Decimal.precision = Math.random() * 10 + 1 | 0;
r = Decimal.random();
} else {
dp = Math.random() * 10 | 0;
r = Decimal.random(dp);
}
//log(' limit: ' + limit);
//log(r.toString());
T(limit);
if ( r.c[0] ) {
j = r.c.length;
k = r.c[j - 1];
j *= 7;
// Precision. Integer 1 - 80.
pr = Math.random() * 80 + 1 | 0;
//log(' pr: ' + pr);
T(limit, pr);
// Decrement for trailing zeros in last element of r.c.
for ( ; k % 10 === 0; k /= 10, j-- );
} else {
j = 0;
}
Decimal.config({ crypto: true });
// Check number of decimal places (j is actual dp).
if ( j > dp ) {
m = ' r.c.length - r.e - 1 > dp';
// Check 0 <= r < 1
} else if ( r.lt(0) || r.gte(1) ) {
m = ' r.lt(0) || r.gte(1)';
// Check that the attributes of r are formed correctly.
} else if ( !r.eq( new Decimal(r) ) || !r.eq( new Decimal( r.toString() ) ) ) {
m = ' !r.eq( new Decimal(r) ) || !r.eq( new Decimal( r.toString() ) )';
}
total++;
if (m) {
error('\n Test number: ' + total + ' failed');
error(m);
error(' r: ' + r);
error(' r.c: ' + r.c);
error(' r.e: ' + r.e);
error(' r.s: ' + r.s);
error(' dp: ' + dp);
m = null;
} else {
passed++;
}
}
assertException(function () { Decimal.random(Infinity) }, 'Infinity');

View File

@ -15,7 +15,7 @@ var count = (function toFixed(Decimal) {
str.replace('\n', '<br>') + '</div>' };
}
if (!Decimal && typeof require === 'function') Decimal = require('../decimal');
if (!Decimal && typeof require === 'function') Decimal = require('../decimal.js');
function assert(expected, actual) {
total++;
@ -1051,11 +1051,8 @@ var count = (function toFixed(Decimal) {
T('123.45000000000', '12.345e1', '1.1e1');
T('123.5', '12.345e1', 1);
T('120', '12.345e1', '-1');
T('0', '12.345e1', -23);
T('123.45', '12.345e1', '-1');
T('123.45', '12.345e1', 1e9 + 1);
T('123', '12.345e1', '-0.01');
T('123', '12.345e1', '-1e-1');
T('123.45', '12.345e1', Infinity);
T('123.45', '12.345e1', '-Infinity');
@ -1070,7 +1067,7 @@ var count = (function toFixed(Decimal) {
T('1', 0.55, 0);
T('1', 0.56, 0);
T('-1', -0.54, 0);
T('-0', -0.5, 0); // test no. 1307
T('-0', -0.5, 0);
T('-1', -0.56, 0);
T('-0.5', -0.5, 1);
T('1.3', 1.25, 1);
@ -1119,27 +1116,6 @@ var count = (function toFixed(Decimal) {
T('-1.00000000000000000', '-1.000000000000000000005', '17')
T('-1.00000000000000000001', '-1.000000000000000000005', '20')
Decimal.rounding = 4;
T('1000', 999.5, -1);
T('1000', 999.5, -2);
T('1000', 999.5, -3);
T('0', 999.5, -4);
T('0', 999.5, -5);
T('0', 0.000123456, -1);
T('9870', 9870.000123456, -1);
T('9900', 9870.000123456, -2);
T('10000', 9870.000123456, -3);
Decimal.rounding = 1;
T('990', 999.5, -1);
T('900', 999.5, -2);
T('0', 999.5, -3);
T('0', 999.5, -4);
T('0', 999.5, -5);
log('\n ' + passed + ' of ' + total + ' tests passed in ' + (+new Date() - start) + ' ms \n');
return [passed, total];
})(this.Decimal);