Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
95 changes: 89 additions & 6 deletions docs/datatypes/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ The supported data types are:

- Boolean
- [Number](numbers.md)
- [BigInt](bigints.md)
- [BigNumber](bignumbers.md)
- [Complex](complex_numbers.md)
- [Fraction](fractions.md)
Expand All @@ -20,7 +21,75 @@ The supported data types are:
Function [`math.typeOf(x)`](../reference/functions/typeOf.md) can be used to get
the type of a variable.

Example usage:
## Type conversions

### Implicit

For convenience, mathjs will automatically attempt certain type conversions
on the actual arguments to its functions, in order to match the declared
parameter types of the function. For example, there is such an implicit
conversion of boolean values to number values, that takes `false` to 0 and
`true` to 1. Therefore, the invocation `math.add(3, true)` matches the mathjs
add function with two parameters of type `number`, and returns the value 4.

Note that booleans will implicitly convert to any other scalar type,
and strings will implicitly convert to any other scalar type except boolean,
by interpreting the string as the printed representation of a numerical value.
And here is an ASCII art diagram of all other implicit conversions in effect
as of mathjs 14:

```
/------------> Fraction
/ / \
BigInt----------\/ \
\ /-> BigNumber /
-> Number | /
/ \ v L
Boolean \--> Complex

Array <--> Matrix
```

(Note that the diagram is not "transitive", or in other words, even though
there is an implicit conversion from Boolean to Number and Number to Complex,
there is _not_ any implicit conversion from Boolean to Complex.)

All of these implicit conversions are "safe" in that they will throw an
error if performing them would cause either a loss of precision (e.g.,
losing significant digits when converting a 20-digit bigint to a number),
or an illusory gain in precision (e.g., converting a number with 16 decimal
places, the last one or two of which are likely numerically approximate,
into a bignumber that purports to have 64 digits of precision).

### Explicit

In addition, for each type, there is an explicit function that serves as
a way to "construct" instances of that type, or equivalently, request
explicit conversion of any other type into that type. The name of this
constructor/converter is always the name of the type with all letters
changed to lower case.

Note that such an explicit conversion will throw an error if it would
discard some portion of the content of the value to be converted. So for
example, converting `'6.2831853'` to `number` will succeed, but
`'6.2831853 ~= tau'` to `number` will fail because the non-numeric
characters would be discarded. Similarly, `bigint(complex(-12, 0))` will
succeed and return `-12n` because there is no imaginary part to "-12 + 0i",
but `bigint(complex(-12, 3))` will throw an error because the imaginary
part "3i" would be discarded.

Otherwise, the explicit conversions are by default "unsafe", in that they
will produce the value of the requested type that most closely approximates
the numeric value of the supplied argument, even if rounding must occur or
(apparent) precision is lost or gained. Thus, `bigint(6.283)` will return
`6n`. However, you may supply an options object as a final argument to the
conversion, and if it includes the key "safe" with a true value, a safe
conversion, equivalent to that used in implicit conversion, will be
performed instead. See the documentation pages for the individual
constructor functions for details on any other options available in
specific cases.

## Examples of using types with mathjs functions:

```js
// use numbers
Expand All @@ -35,11 +104,11 @@ math.add(math.bignumber(0.1), math.bignumber(0.2)) // BigNumber, 0.3
math.add(300000000000000000n, 1n) // 300000000000000001n

// use Fractions
math.add(math.fraction(1), math.fraction(3)) // Fraction, 0.(3)
math.divide(math.fraction(1), math.fraction(3)) // Fraction, 0.(3)

// use strings
math.add('hello ', 'world') // 'hello world'
math.max('A', 'D', 'C') // 'D'
math.concat('hello ', 'world') // 'hello world'
math.sort(['A', 'D', 'C'], 'natural')[2] // 'D'

// use complex numbers
const a = math.complex(2, 3) // 2 + 3i
Expand All @@ -52,11 +121,11 @@ math.sqrt(-4) // 2i
// use arrays
const array = [1, 2, 3, 4, 5]
math.factorial(array) // Array, [1, 2, 6, 24, 120]
math.add(array, 3) // Array, [3, 5, 6, 7, 8]
math.add(array, 3) // Array, [4, 5, 6, 7, 8]

// use matrices
const matrix = math.matrix([1, 4, 9, 16, 25]) // Matrix, [1, 4, 9, 16, 25]
math.sqrt(matrix) // Matrix, [1, 2, 3, 4, 5]
math.map(matrix, math.sqrt) // Matrix, [1, 2, 3, 4, 5]

// use units
const a = math.unit(55, 'cm') // 550 mm
Expand All @@ -67,4 +136,18 @@ math.add(a, b) // 0.65 m
math.typeOf(2) // 'number'
math.typeOf(math.unit('2 inch')) // 'Unit'
math.typeOf(math.sqrt(-4)) // 'Complex'

// bigints implicitly convert to numbers (for example):
math.add(6.283, 3n) // 9.283
math.sqrt(20000n) // 141.42135623731
// But they guard against accidentally losing precision:
math.sqrt(12345678901234567890n) // throws "value exceeds the max safe integer"

// You can request explicit conversion
math.add(math.bigint(6.283), 3n) // 9n
// And such explicit requests are unsafe by default:
math.sqrt(math.number(12345678901234567890n)) // 3.5136418288201e+9
// But you can turn safety back on:
math.sqrt(math.number(12345678901234567890n, {safe: true}))
// throws "value exceed the max safe integer"
```
7 changes: 5 additions & 2 deletions src/core/function/import.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,17 +45,20 @@ export function importFactory (typed, load, math, importedFactories) {
* return 'hello, ' + name + '!'
* }
* })
*
* // use the imported function and variable
* math.myvalue * 2 // 84
*
* math.hello('user') // 'hello, user!'
*
* // import the npm module 'numbers'
* // (must be installed first with `npm install numbers`)
* math.import(numbers, {wrap: true})
*
* math.fibonacci(7) // returns 13
*
* See also:
*
* create, all
*
* @param {Object | Array} functions Object with functions to be imported.
* @param {Object} [options] Import options.
*/
Expand Down
13 changes: 8 additions & 5 deletions src/expression/parse.js
Original file line number Diff line number Diff line change
Expand Up @@ -66,14 +66,17 @@ export const createParse = /* #__PURE__ */ factory(name, dependencies, ({
* node1.compile().evaluate() // 5
*
* let scope = {a:3, b:4}
* const node2 = math.parse('a * b') // 12
* const node2 = math.parse('a * b')
* node2.evaluate(scope) // 12
* const code2 = node2.compile()
* code2.evaluate(scope) // 12
* scope.b = 5
* code2.evaluate(scope) // 15
* scope.a = 5
* code2.evaluate(scope) // 20
* code2.evaluate(scope) // 25
*
* const nodes = math.parse(['a = 3', 'b = 4', 'a * b'])
* nodes[2].compile().evaluate() // 12
* const nodes = math.parse(['a = 3', 'b = 2', 'a * b'])
* const newscope = {}
* nodes.map(node => node.compile().evaluate(newscope)) // [3, 2, 6]
*
* See also:
*
Expand Down
26 changes: 13 additions & 13 deletions src/function/algebra/rationalize.js
Original file line number Diff line number Diff line change
Expand Up @@ -75,24 +75,24 @@ export const createRationalize = /* #__PURE__ */ factory(name, dependencies, ({
* Examples:
*
* math.rationalize('sin(x)+y')
* // Error: There is an unsolved function call
* math.rationalize('2x/y - y/(x+1)')
* // (2*x^2-y^2+2*x)/(x*y+y)
* math.rationalize('(2x+1)^6')
* // 64*x^6+192*x^5+240*x^4+160*x^3+60*x^2+12*x+1
* // throws Error: There is an unsolved function call
* math.rationalize('2x/y - y/(x+1)') // (2*x^2-y^2+2*x)/(x*y+y)
* // math.rationalize('(2x+1)^6') // hangs, see #3351
* // returns 64*x^6+192*x^5+240*x^4+160*x^3+60*x^2+12*x+1
* math.rationalize('2x/( (2x-1) / (3x+2) ) - 5x/ ( (3x+4) / (2x^2-5) ) + 3')
* // -20*x^4+28*x^3+104*x^2+6*x-12)/(6*x^2+5*x-4)
* math.rationalize('x/(1-x)/(x-2)/(x-3)/(x-4) + 2x/ ( (1-2x)/(2-3x) )/ ((3-4x)/(4-5x) )') =
* // (-30*x^7+344*x^6-1506*x^5+3200*x^4-3472*x^3+1846*x^2-381*x)/
* // (-8*x^6+90*x^5-383*x^4+780*x^3-797*x^2+390*x-72)
* // returns -20*x^4+28*x^3+104*x^2+6*x-12)/(6*x^2+5*x-4)
* // math.rationalize('x/(1-x)/(x-2)/(x-3)/(x-4) + 2x/ ( (1-2x)/(2-3x) )/ ((3-4x)/(4-5x) )') // hangs, see #3351
* // returns (-30*x^7+344*x^6-1506*x^5+3200*x^4-3472*x^3+1846*x^2-381*x)/(-8*x^6+90*x^5-383*x^4+780*x^3-797*x^2+390*x-72)
*
* math.rationalize('x+x+x+y',{y:1}) // 3*x+1
* math.rationalize('x+x+x+y',{}) // 3*x+y
*
* const ret = math.rationalize('x+x+x+y',{},true)
* // ret.expression=3*x+y, ret.variables = ["x","y"]
* const ret = math.rationalize('-2+5x^2',{},true)
* // ret.expression=5*x^2-2, ret.variables = ["x"], ret.coefficients=[-2,0,5]
* const r = math.rationalize('x+x+x+y',{},true);
* [r.expression.toString(), r.variables] // ['3 * x + y', ['x', 'y']]
*
* const ret = math.rationalize('-2+5x^2',{},true);
* [ret.expression.toString(), ret.variables, ret.coefficients]
* // returns ['5 * x ^ 2 - 2', ['x'], [-2,0,5]]
*
* See also:
*
Expand Down
2 changes: 1 addition & 1 deletion src/function/algebra/solver/lsolve.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ export const createLsolve = /* #__PURE__ */ factory(name, dependencies, ({ typed
*
* const a = [[-2, 3], [2, 1]]
* const b = [11, 9]
* const x = lsolve(a, b) // [[-5.5], [20]]
* math.lsolve(a, b) // [[-5.5], [20]]
*
* See also:
*
Expand Down
2 changes: 1 addition & 1 deletion src/function/algebra/solver/lsolveAll.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ export const createLsolveAll = /* #__PURE__ */ factory(name, dependencies, ({ ty
*
* const a = [[-2, 3], [2, 1]]
* const b = [11, 9]
* const x = lsolveAll(a, b) // [ [[-5.5], [20]] ]
* math.lsolveAll(a, b) // [ [[-5.5], [20]] ]
*
* See also:
*
Expand Down
2 changes: 1 addition & 1 deletion src/function/algebra/solver/usolve.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ export const createUsolve = /* #__PURE__ */ factory(name, dependencies, ({ typed
*
* const a = [[-2, 3], [2, 1]]
* const b = [11, 9]
* const x = usolve(a, b) // [[8], [9]]
* math.usolve(a, b) // [[8], [9]]
*
* See also:
*
Expand Down
2 changes: 1 addition & 1 deletion src/function/algebra/solver/usolveAll.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ export const createUsolveAll = /* #__PURE__ */ factory(name, dependencies, ({ ty
*
* const a = [[-2, 3], [2, 1]]
* const b = [11, 9]
* const x = usolveAll(a, b) // [ [[8], [9]] ]
* math.usolveAll(a, b) // [ [[8], [9]] ]
*
* See also:
*
Expand Down
2 changes: 1 addition & 1 deletion src/function/arithmetic/add.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ export const createAdd = /* #__PURE__ */ factory(
*
* const c = math.unit('5 cm')
* const d = math.unit('2.1 mm')
* math.add(c, d) // returns Unit 52.1 mm
* math.add(c, d) // returns Unit 5.21 cm
*
* math.add("2.3", "4") // returns number 6.3
*
Expand Down
7 changes: 2 additions & 5 deletions src/function/arithmetic/cbrt.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,8 @@ export const createCbrt = /* #__PURE__ */ factory(name, dependencies, ({ config,
*
* const x = math.complex('8i')
* math.cbrt(x) // returns Complex 1.7320508075689 + i
* math.cbrt(x, true) // returns Matrix [
* // 1.7320508075689 + i
* // -1.7320508075689 + i
* // -2i
* // ]
* math.cbrt(x, true)
* // returns [1.7320508075689 + i, -1.7320508075689 + i, -2i]
*
* See also:
*
Expand Down
5 changes: 2 additions & 3 deletions src/function/arithmetic/dotDivide.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,8 @@ export const createDotDivide = /* #__PURE__ */ factory(name, dependencies, ({ ty
*
* math.dotDivide(2, 4) // returns 0.5
*
* a = [[9, 5], [6, 1]]
* b = [[3, 2], [5, 2]]
*
* const a = [[9, 5], [6, 1]]
* const b = [[3, 2], [5, 2]]
* math.dotDivide(a, b) // returns [[3, 2.5], [1.2, 0.5]]
* math.divide(a, b) // returns [[1.75, 0.75], [-1.75, 2.25]]
*
Expand Down
5 changes: 2 additions & 3 deletions src/function/arithmetic/dotMultiply.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,8 @@ export const createDotMultiply = /* #__PURE__ */ factory(name, dependencies, ({
*
* math.dotMultiply(2, 4) // returns 8
*
* a = [[9, 5], [6, 1]]
* b = [[3, 2], [5, 2]]
*
* const a = [[9, 5], [6, 1]]
* const b = [[3, 2], [5, 2]]
* math.dotMultiply(a, b) // returns [[27, 10], [30, 2]]
* math.multiply(a, b) // returns [[52, 28], [23, 14]]
*
Expand Down
10 changes: 9 additions & 1 deletion src/function/arithmetic/log.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,13 @@ export const createLog = /* #__PURE__ */ factory(name, dependencies, ({ typed, t
* To avoid confusion with the matrix logarithm, this function does not
* apply to matrices.
*
* Note that when the value is a Fraction, then the
* base must be specified as a Fraction, and the log() will only be
* returned when the result happens to be rational. When there is an
* attempt to take a log of Fractions that would result in an irrational
* value, a TypeError against implicit conversion of BigInt to Fraction
* is thrown.
*
* Syntax:
*
* math.log(x)
Expand All @@ -38,7 +45,8 @@ export const createLog = /* #__PURE__ */ factory(name, dependencies, ({ typed, t
* Value for which to calculate the logarithm.
* @param {number | BigNumber | Fraction | Complex} [base=e]
* Optional base for the logarithm. If not provided, the natural
* logarithm of `x` is calculated.
* logarithm of `x` is calculated, unless x is a Fraction, in
* which case an error is thrown.
* @return {number | BigNumber | Fraction | Complex}
* Returns the logarithm of `x`
*/
Expand Down
15 changes: 7 additions & 8 deletions src/function/logical/and.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,9 @@ export const createAnd = /* #__PURE__ */ factory(name, dependencies, ({ typed, m
*
* math.and(2, 4) // returns true
*
* a = [2, 0, 0]
* b = [3, 7, 0]
* c = 0
*
* const a = [2, 0, 0]
* const b = [3, 7, 0]
* const c = 0
* math.and(a, b) // returns [true, false, false]
* math.and(a, c) // returns [false, false, false]
*
Expand Down Expand Up @@ -72,17 +71,17 @@ export const createAnd = /* #__PURE__ */ factory(name, dependencies, ({ typed, m
'SparseMatrix, any': typed.referToSelf(self => (x, y) => {
// check scalar
if (not(y)) {
// return zero matrix
return zeros(x.size(), x.storage())
// return all false matrix
return matrix([], x.storage()).resize(x.size(), false)
}
return matAlgo11xS0s(x, y, self, false)
}),

'DenseMatrix, any': typed.referToSelf(self => (x, y) => {
// check scalar
if (not(y)) {
// return zero matrix
return zeros(x.size(), x.storage())
// return all false matrix
return matrix().resize(x.size(), false)
}
return matAlgo14xDs(x, y, self, false)
}),
Expand Down
2 changes: 1 addition & 1 deletion src/function/logical/not.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ export const createNot = /* #__PURE__ */ factory(name, dependencies, ({ typed })
* math.not(0) // returns true
* math.not(true) // returns false
*
* a = [2, -7, 0]
* const a = [2, -7, 0]
* math.not(a) // returns [false, false, true]
*
* See also:
Expand Down
7 changes: 3 additions & 4 deletions src/function/logical/or.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,9 @@ export const createOr = /* #__PURE__ */ factory(name, dependencies, ({ typed, ma
*
* math.or(2, 4) // returns true
*
* a = [2, 5, 0]
* b = [0, 22, 0]
* c = 0
*
* const a = [2, 5, 0]
* const b = [0, 22, 0]
* const c = 0
* math.or(a, b) // returns [true, true, false]
* math.or(b, c) // returns [false, true, false]
*
Expand Down
7 changes: 3 additions & 4 deletions src/function/logical/xor.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,9 @@ export const createXor = /* #__PURE__ */ factory(name, dependencies, ({ typed, m
*
* math.xor(2, 4) // returns false
*
* a = [2, 0, 0]
* b = [2, 7, 0]
* c = 0
*
* const a = [2, 0, 0]
* const b = [2, 7, 0]
* const c = 0
* math.xor(a, b) // returns [false, true, false]
* math.xor(a, c) // returns [true, false, false]
*
Expand Down
Loading