Implemented configuration value {number: 'fraction'}. Added docs and example for fractions.

This commit is contained in:
jos 2015-05-12 14:40:47 +02:00
parent a0ad13b9e0
commit 0c1e9deeeb
12 changed files with 161 additions and 24 deletions

View File

@ -3,6 +3,7 @@
## not yet released, version 2.0.0-SNAPSHOT
- Implemented support for fractions, powered by the library `fraction.js`.
- Implemented matrix LU decomposition with partial pivoting and a LU based
linear equations solver (functions `lup` and `lusolve`). Thanks @rjbaucells.
- Large internal refactoring, allowing to create custom bundles of math.js.

View File

@ -10,7 +10,7 @@ Powerful and easy to use.
## Features
- Supports numbers, big numbers, complex numbers, units, strings, arrays, and matrices.
- Supports numbers, big numbers, complex numbers, fractions, units, strings, arrays, and matrices.
- Is compatible with JavaScript's built-in Math library.
- Contains a flexible expression parser.
- Supports chained operations.

View File

@ -24,12 +24,14 @@ The following configuration options are available:
inputs, a matrix will be returned always.
- `number`. The default type of numbers. This setting is used by functions
like `eval `which cannot determine the correct type of output from the
like `eval` which cannot determine the correct type of output from the
functions input. For most functions though, the type of output is determined
from the the input: a number as input will return a number as output,
a BigNumber as input returns a BigNumber as output.
Available values are: `'number'` (default) or `'bignumber'`.
BigNumbers have higher precision than the default numbers of JavaScript.
Available values are: `'number'` (default), `'bignumber'`, or `'fraction'`.
[BigNumbers](./datatypes/bignumbers.js) have higher precision than the default
numbers of JavaScript, and [`Fractions`](./datatypes/fractions.js) store
values in terms of a numerator and denominator.
- `precision`. The maximum number of significant digits for bigNumbers.
This setting only applies to BigNumbers, not to numbers.
@ -76,7 +78,7 @@ math2.range(0, 4); // Matrix [0, 1, 2, 3]
// create an instance of math.js with bignumber configuration
var bigmath = math.create({
number: 'bignumber', // Choose 'number' (default) or 'bignumber'
number: 'bignumber', // Choose 'number' (default), 'bignumber', or 'fraction'
precision: 32 // 64 by default, only applicable for BigNumbers
});
@ -110,7 +112,7 @@ bigmath.eval('1 / 3'); // BigNumber, 0.33333333333333333333333333333333
// create a new instance of math.js with bignumber configuration
var bigmath = math.create({
number: 'bignumber', // Choose 'number' (default) or 'bignumber'
number: 'bignumber', // Choose 'number' (default), 'bignumber', or 'fraction'
precision: 32 // 64 by default, only applicable for BigNumbers
});

View File

@ -21,7 +21,8 @@ BigNumbers instead of [numbers](numbers.md) by default, configure math.js like:
```js
math.config({
number: 'bignumber', // Default type of number: 'number' (default) or 'bignumber'
number: 'bignumber', // Default type of number:
// 'number' (default), 'bignumber', or 'fraction'
precision: 64 // Number of significant digits for BigNumbers
});
@ -83,21 +84,21 @@ console.log(ans.toString());
## Conversion
BigNumbers can be converted to numbers and vice versa using the functions
`number` and `bignumber`. When converting a BigNumber to a Number, the high
`number` and `bignumber`. When converting a BigNumber to a number, the high
precision of the BigNumber will be lost. When a BigNumber is too large to be represented
as Number, it will be initialized as `Infinity`.
```js
// converting numbers and BigNumbers
var a = math.number(0.3); // Number, 0.3
var a = math.number(0.3); // number, 0.3
var b = math.bignumber(a); // BigNumber, 0.3
var c = math.number(b); // Number, 0.3
var c = math.number(b); // number, 0.3
// exceeding the maximum of a number
var d = math.bignumber('1.2e500'); // BigNumber, 1.2e+500
var e = math.number(d); // Number, Infinity
var e = math.number(d); // number, Infinity
// loosing precision when converting to number
var f = math.bignumber('0.2222222222222222222'); // BigNumber, 0.2222222222222222222
var g = math.number(f); // Number, 0.2222222222222222
var g = math.number(f); // number, 0.2222222222222222
```

View File

@ -0,0 +1,66 @@
# Fractions
For calculations with fractions, math.js supports a `Fraction` data type.
Fraction support is powered by [fraction.js](https://github.com/infusion/Fraction.js).
Unlike [numbers](numbers.md) and [BigNumbers](./bignumbers.md), fractions can
store numbers with infinitely repeating decimals, for example `1/3 = 0.3333333...`,
which can be represented as `0.(3)`, or `2/7` which can be represented as `0.(285714)`.
## Usage
A Fraction can be created using the function `fraction`:
```js
math.fraction('1/3'); // Fraction, 0.(3)
math.fraction(1, 3); // Fraction, 0.(3)
math.fraction('0.(3)'); // Fraction, 0.(3)
```
And can be used in functions like `add` and `multiply` like:
```js
math.add(fraction('1/3'), fraction('1/6')); // Fraction, 0.5
math.multiply(fraction('1/4'), fraction('1/2')); // Fraction, 0.125
```
Note that not all functions support fractions. For example trigonometric
functions doesn't support fractions. When not supported, the functions
will convert the input to numbers and return a number as result.
Most functions will determine the type of output from the type of input:
a number as input will return a number as output, a Fraction as input returns
a Fraction as output. Functions which cannot determine the type of output
from the input (for example `math.eval`) use the default number type `number`,
which can be configured when instantiating math.js. To configure the use of
fractions instead of [numbers](numbers.md) by default, configure math.js like:
```js
// Configure the default type of number: 'number' (default), 'bignumber', or 'fraction'
math.config({
number: 'fraction'
});
// use math
math.eval('0.1 + 0.2'); // Fraction, 0.3
```
## Conversion
Fractions can be converted to numbers and vice versa using the functions
`number` and `fraction`. When converting a Fraction to a number, precision
may be lost when the value cannot represented in 16 digits.
```js
// converting numbers and fractions
var a = math.number(0.3); // number, 0.3
var b = math.fraction(a); // Fraction, 0.3
var c = math.number(b); // number, 0.3
// loosing precision when converting to number: a fraction can represent
// a number with an infinite number of repeating decimals, a number just
// stores about 16 digits and cuts consecutive digits.
var d = math.fraction('1/3'); // Fraction, 0.(3)
var e = math.number(f); // number, 0.3333333333333333
```

View File

@ -11,6 +11,7 @@ The supported data types are:
- [Number](numbers.md)
- [BigNumber](bignumbers.md)
- [Complex](complex_numbers.md)
- [Fraction](fractions.md)
- [Array](matrices.md)
- [Matrix](matrices.md)
- [Unit](units.md)
@ -27,6 +28,9 @@ math.sqrt(4.41e2); // 21
// use BigNumbers
math.add(math.bignumber(0.1), math.bignumber(0.2)); // BigNumber, 0.3
// use Fractions
math.add(math.fraction(1), math.fraction(3)); // Fraction, 0.(3)
// use strings
math.add('hello ', 'world'); // 'hello world'
math.max('A', 'D', 'C'); // 'D'

View File

@ -16,7 +16,8 @@ can be configured when instantiating math.js:
```js
math.config({
number: 'number' // Default type of number: 'number' (default) or 'bignumber'
number: 'number' // Default type of number:
// 'number' (default), 'bignumber', or 'fraction'
});
```

View File

@ -272,7 +272,7 @@ The default number type of the expression parser can be changed at instantiation
of math.js. The expression parser parses numbers as BigNumber by default:
```js
// Configure the type of number: 'number' (default) or 'bignumber'
// Configure the type of number: 'number' (default), 'bignumber', or 'fraction'
math.config({number: 'bignumber'});
// all numbers are parsed as BigNumber

View File

@ -5,18 +5,11 @@ var math = require('../index');
// configure the default type of numbers as BigNumbers
math.config({
number: 'bignumber', // Default type of number: 'number' (default) or 'bignumber'
number: 'bignumber', // Default type of number:
// 'number' (default), 'bignumber', or 'fraction'
precision: 20 // Number of significant digits for BigNumbers
});
/**
* Helper function to output a value in the console. Value will be formatted.
* @param {*} value
*/
function print (value) {
console.log(math.format(value));
}
console.log('round-off errors with numbers');
print(math.add(0.1, 0.2)); // Number, 0.30000000000000004
print(math.divide(0.3, 0.2)); // Number, 1.4999999999999998
@ -38,3 +31,11 @@ console.log('use BigNumbers in the expression parser');
print(math.eval('0.1 + 0.2')); // BigNumber, 0.3
print(math.eval('0.3 / 0.2')); // BigNumber, 1.5
console.log();
/**
* Helper function to output a value in the console. Value will be formatted.
* @param {*} value
*/
function print (value) {
console.log(math.format(value));
}

42
examples/fractions.js Normal file
View File

@ -0,0 +1,42 @@
// Fractions
// load math.js
var math = require('../index');
// configure the default type of numbers as Fractions
math.config({
number: 'fraction' // Default type of number:
// 'number' (default), 'bignumber', or 'fraction'
});
console.log('round-off errors with numbers');
print(math.add(0.1, 0.2)); // Number, 0.30000000000000004
print(math.divide(0.3, 0.2)); // Number, 1.4999999999999998
console.log();
console.log('no round-off errors with Fractions');
print(math.add(math.fraction(0.1), math.fraction(0.2))); // Fraction, 0.3
print(math.divide(math.fraction(0.3), math.fraction(0.2))); // Fraction, 1.5
console.log();
console.log('Represent an infinite number of repeating digits');
print(math.fraction('1/3')); // Fraction, 0.(3)
print(math.fraction('2/7')); // Fraction, 0.(285714)
print(math.fraction('23/11')); // Fraction, 2.(09)
console.log();
// one can work conveniently with fractions using the expression parser.
// note though that Fractions are only supported by basic arithmetic functions
console.log('use fractions in the expression parser');
print(math.eval('0.1 + 0.2')); // Fraction, 0.3
print(math.eval('0.3 / 0.2')); // Fraction, 1.5
print(math.eval('23 / 11')); // Fraction, 2.(09)
console.log();
/**
* Helper function to output a value in the console. Value will be formatted.
* @param {*} value
*/
function print (value) {
console.log(math.format(value));
}

View File

@ -87,9 +87,14 @@ function factory (type, config, load, typed) {
ConstantNode.prototype._compile = function (defs) {
switch (this.valueType) {
case 'number':
if (defs.math.config().number === 'bignumber') {
// TODO: replace this with using config.number
var numConfig = defs.math.config().number;
if (numConfig === 'bignumber') {
return 'math.bignumber("' + this.value + '")';
}
else if (numConfig === 'fraction') {
return 'math.fraction("' + this.value + '")';
}
else {
// remove leading zeros like '003.2' which are not allowed by JavaScript
return this.value.replace(/^(0*)[0-9]/, function (match, zeros) {

View File

@ -203,6 +203,20 @@ describe('parse', function() {
});
describe('fraction', function () {
it('should output fractions if default number type is fraction', function() {
var fmath = math.create({
number: 'fraction'
});
assert(parse('0.1').compile(fmath).eval() instanceof math.type.Fraction);
assert.equal(parse('1/3').compile(fmath).eval().toString(), '0.(3)');
assert.equal(parse('0.1+0.2').compile(fmath).eval().toString(), '0.3');
});
});
describe('string', function () {
it('should parse a string', function() {