Skip to content

Commit 2fae716

Browse files
committed
doc: document systematized type conversion principles
1 parent f2b4f52 commit 2fae716

File tree

1 file changed

+89
-6
lines changed

1 file changed

+89
-6
lines changed

docs/datatypes/index.md

Lines changed: 89 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ The supported data types are:
99

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

23-
Example usage:
24+
## Type conversions
25+
26+
### Implicit
27+
28+
For convenience, mathjs will automatically attempt certain type conversions
29+
on the actual arguments to its functions, in order to match the declared
30+
parameter types of the function. For example, there is such an implicit
31+
conversion of boolean values to number values, that takes `false` to 0 and
32+
`true` to 1. Therefore, the invocation `math.add(3, true)` matches the mathjs
33+
add function with two parameters of type `number`, and returns the value 4.
34+
35+
Note that booleans will implicitly convert to any other scalar type,
36+
and strings will implicitly convert to any other scalar type except boolean,
37+
by interpreting the string as the printed representation of a numerical value.
38+
And here is an ASCII art diagram of all other implicit conversions in effect
39+
as of mathjs 14:
40+
41+
```
42+
/------------> Fraction
43+
/ / \
44+
BigInt----------\/ \
45+
\ /-> BigNumber /
46+
-> Number | /
47+
/ \ v L
48+
Boolean \--> Complex
49+
50+
Array <--> Matrix
51+
```
52+
53+
(Note that the diagram is not "transitive", or in other words, even though
54+
there is an implicit conversion from Boolean to Number and Number to Complex,
55+
there is _not_ any implicit conversion from Boolean to Complex.)
56+
57+
All of these implicit conversions are "safe" in that they will throw an
58+
error if performing them would cause either a loss of precision (e.g.,
59+
losing significant digits when converting a 20-digit bigint to a number),
60+
or an illusory gain in precision (e.g., converting a number with 16 decimal
61+
places, the last one or two of which are likely numerically approximate,
62+
into a bignumber that purports to have 64 digits of precision).
63+
64+
### Explicit
65+
66+
In addition, for each type, there is an explicit function that serves as
67+
a way to "construct" instances of that type, or equivalently, request
68+
explicit conversion of any other type into that type. The name of this
69+
constructor/converter is always the name of the type with all letters
70+
changed to lower case.
71+
72+
Note that such an explicit conversion will throw an error if it would
73+
discard some portion of the content of the value to be converted. So for
74+
example, converting `'6.2831853'` to `number` will succeed, but
75+
`'6.2831853 ~= tau'` to `number` will fail because the non-numeric
76+
characters would be discarded. Similarly, `bigint(complex(-12, 0))` will
77+
succeed and return `-12n` because there is no imaginary part to "-12 + 0i",
78+
but `bigint(complex(-12, 3))` will throw an error because the imaginary
79+
part "3i" would be discarded.
80+
81+
Otherwise, the explicit conversions are by default "unsafe", in that they
82+
will produce the value of the requested type that most closely approximates
83+
the numeric value of the supplied argument, even if rounding must occur or
84+
(apparent) precision is lost or gained. Thus, `bigint(6.283)` will return
85+
`6n`. However, you may supply an options object as a final argument to the
86+
conversion, and if it includes the key "safe" with a true value, a safe
87+
conversion, equivalent to that used in implicit conversion, will be
88+
performed instead. See the documentation pages for the individual
89+
constructor functions for details on any other options available in
90+
specific cases.
91+
92+
## Examples of using types with mathjs functions:
2493

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

37106
// use Fractions
38-
math.add(math.fraction(1), math.fraction(3)) // Fraction, 0.(3)
107+
math.divide(math.fraction(1), math.fraction(3)) // Fraction, 0.(3)
39108

40109
// use strings
41-
math.add('hello ', 'world') // 'hello world'
42-
math.max('A', 'D', 'C') // 'D'
110+
math.concat('hello ', 'world') // 'hello world'
111+
math.sort(['A', 'D', 'C'], 'natural')[2] // 'D'
43112

44113
// use complex numbers
45114
const a = math.complex(2, 3) // 2 + 3i
@@ -52,11 +121,11 @@ math.sqrt(-4) // 2i
52121
// use arrays
53122
const array = [1, 2, 3, 4, 5]
54123
math.factorial(array) // Array, [1, 2, 6, 24, 120]
55-
math.add(array, 3) // Array, [3, 5, 6, 7, 8]
124+
math.add(array, 3) // Array, [4, 5, 6, 7, 8]
56125

57126
// use matrices
58127
const matrix = math.matrix([1, 4, 9, 16, 25]) // Matrix, [1, 4, 9, 16, 25]
59-
math.sqrt(matrix) // Matrix, [1, 2, 3, 4, 5]
128+
math.map(matrix, math.sqrt) // Matrix, [1, 2, 3, 4, 5]
60129

61130
// use units
62131
const a = math.unit(55, 'cm') // 550 mm
@@ -67,4 +136,18 @@ math.add(a, b) // 0.65 m
67136
math.typeOf(2) // 'number'
68137
math.typeOf(math.unit('2 inch')) // 'Unit'
69138
math.typeOf(math.sqrt(-4)) // 'Complex'
139+
140+
// bigints implicitly convert to numbers (for example):
141+
math.add(6.283, 3n) // 9.283
142+
math.sqrt(20000n) // 141.42135623731
143+
// But they guard against accidentally losing precision:
144+
math.sqrt(12345678901234567890n) // throws "value exceeds the max safe integer"
145+
146+
// You can request explicit conversion
147+
math.add(math.bigint(6.283), 3n) // 9n
148+
// And such explicit requests are unsafe by default:
149+
math.sqrt(math.number(12345678901234567890n)) // 3.5136418288201e+9
150+
// But you can turn safety back on:
151+
math.sqrt(math.number(12345678901234567890n, {safe: true}))
152+
// throws "value exceed the max safe integer"
70153
```

0 commit comments

Comments
 (0)