Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
11 changes: 11 additions & 0 deletions src/function/arithmetic/log.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { logNumber } from '../../plain/number/index.js'

const name = 'log'
const dependencies = ['config', 'typed', 'typeOf', 'divideScalar', 'Complex']
const nlg16 = Math.log(16)

export const createLog = /* #__PURE__ */ factory(name, dependencies, ({ typed, typeOf, config, divideScalar, Complex }) => {
/**
Expand Down Expand Up @@ -50,6 +51,16 @@ export const createLog = /* #__PURE__ */ factory(name, dependencies, ({ typed, t
}
},

bigint: function (x) {
if (x > 0 || config.predictable) {
if (x <= 0) return NaN
const s = x.toString(16)
const s15 = s.substring(0, 15)
return nlg16 * (s.length - s15.length) + logNumber(Number('0x' + s15))
}
return new Complex(x.toNumber(), 0).log()
},

Complex: function (x) {
return x.log()
},
Expand Down
11 changes: 11 additions & 0 deletions src/function/arithmetic/log10.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { log10Number } from '../../plain/number/index.js'

const name = 'log10'
const dependencies = ['typed', 'config', 'Complex']
const log16 = log10Number(16)

export const createLog10 = /* #__PURE__ */ factory(name, dependencies, ({ typed, config, Complex }) => {
/**
Expand Down Expand Up @@ -41,6 +42,16 @@ export const createLog10 = /* #__PURE__ */ factory(name, dependencies, ({ typed,
}
},

bigint: function (x) {
if (x > 0 || config.predictable) {
if (x <= 0) return NaN
const s = x.toString(16)
const s15 = s.substring(0, 15)
return log16 * (s.length - s15.length) + log10Number(Number('0x' + s15))
}
return new Complex(x.toNumber(), 0).log().div(Math.LN10)
},

Complex: function (x) {
return new Complex(x).log().div(Math.LN10)
},
Expand Down
10 changes: 10 additions & 0 deletions src/function/arithmetic/log2.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,16 @@ export const createLog2 = /* #__PURE__ */ factory(name, dependencies, ({ typed,
}
},

bigint: function (x) {
if (x > 0 || config.predictable) {
if (x <= 0) return NaN
const s = x.toString(16)
const s15 = s.substring(0, 15)
return 4 * (s.length - s15.length) + log2Number(Number('0x' + s15))
}
return _log2Complex(new Complex(x.toNumber(), 0))
},

Complex: _log2Complex,

BigNumber: function (x) {
Expand Down
31 changes: 27 additions & 4 deletions src/function/probability/randomInt.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,11 @@ import { createRng } from './util/seededRNG.js'
import { isMatrix } from '../../utils/is.js'

const name = 'randomInt'
const dependencies = ['typed', 'config', '?on']
const dependencies = ['typed', 'config', 'log2', '?on']

export const createRandomInt = /* #__PURE__ */ factory(name, dependencies, ({ typed, config, on }) => {
const simpleCutoff = 2n ** 30n

export const createRandomInt = /* #__PURE__ */ factory(name, dependencies, ({ typed, config, log2, on }) => {
// seeded pseudo random number generator
let rng = createRng(config.randomSeed)

Expand All @@ -24,7 +26,7 @@ export const createRandomInt = /* #__PURE__ */ factory(name, dependencies, ({ ty
*
* Syntax:
*
* math.randomInt() // generate a random integer between 0 and 1
* math.randomInt() // generate either 0 or 1, randomly
* math.randomInt(max) // generate a random integer between 0 and max
* math.randomInt(min, max) // generate a random integer between min and max
* math.randomInt(size) // generate a matrix with random integer between 0 and 1
Expand All @@ -48,9 +50,11 @@ export const createRandomInt = /* #__PURE__ */ factory(name, dependencies, ({ ty
* @return {number | Array | Matrix} A random integer value
*/
return typed(name, {
'': () => _randomInt(0, 1),
'': () => _randomInt(0, 2),
number: (max) => _randomInt(0, max),
'number, number': (min, max) => _randomInt(min, max),
bigint: (max) => _randomBigint(0n, max),
'bigint, bigint': _randomBigint,
'Array | Matrix': (size) => _randomIntMatrix(size, 0, 1),
'Array | Matrix, number': (size, max) => _randomIntMatrix(size, 0, max),
'Array | Matrix, number, number': (size, min, max) => _randomIntMatrix(size, min, max)
Expand All @@ -64,4 +68,23 @@ export const createRandomInt = /* #__PURE__ */ factory(name, dependencies, ({ ty
function _randomInt (min, max) {
return Math.floor(min + rng() * (max - min))
}

function _randomBigint (min, max) {
const width = max - min // number of choices
if (width <= simpleCutoff) { // do it with number type
return min + BigInt(_randomInt(0, Number(width)))
}
// Too big to choose accurately that way. Instead, choose the correct
// number of random bits to cover the width, and repeat until the
// resulting number falls within the width
const bits = log2(width)
let picked = width
while (picked >= width) {
picked = 0n
for (let i = 0; i < bits; ++i) {
picked = 2n * picked + ((rng() < 0.5) ? 0n : 1n)
}
}
return min + picked
}
})
23 changes: 19 additions & 4 deletions src/function/relational/larger.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,20 @@ const name = 'larger'
const dependencies = [
'typed',
'config',
'bignumber',
'matrix',
'DenseMatrix',
'concat',
'SparseMatrix'
]

export const createLarger = /* #__PURE__ */ factory(name, dependencies, ({ typed, config, matrix, DenseMatrix, concat, SparseMatrix }) => {
function bigLarger (config) {
return function (x, y) {
return x.gt(y) && !bigNearlyEqual(x, y, config.relTol, config.absTol)
}
}

export const createLarger = /* #__PURE__ */ factory(name, dependencies, ({ typed, config, bignumber, matrix, DenseMatrix, concat, SparseMatrix }) => {
const matAlgo03xDSf = createMatAlgo03xDSf({ typed })
const matAlgo07xSSf = createMatAlgo07xSSf({ typed, SparseMatrix })
const matAlgo12xSfs = createMatAlgo12xSfs({ typed, DenseMatrix })
Expand Down Expand Up @@ -55,20 +62,28 @@ export const createLarger = /* #__PURE__ */ factory(name, dependencies, ({ typed
* @param {number | BigNumber | bigint | Fraction | boolean | Unit | string | Array | Matrix} y Second value to compare
* @return {boolean | Array | Matrix} Returns true when the x is larger than y, else returns false
*/
const bignumLarger = bigLarger(config)

return typed(
name,
createLargerNumber({ typed, config }),
{
'boolean, boolean': (x, y) => x > y,

'BigNumber, BigNumber': function (x, y) {
return x.gt(y) && !bigNearlyEqual(x, y, config.relTol, config.absTol)
},
'BigNumber, BigNumber': bignumLarger,

'bigint, bigint': (x, y) => x > y,

'Fraction, Fraction': (x, y) => (x.compare(y) === 1),

'Fraction, BigNumber': function (x, y) {
return bignumLarger(bignumber(x), y)
},

'BigNumber, Fraction': function (x, y) {
return bignumLarger(x, bignumber(y))
},

'Complex, Complex': function () {
throw new TypeError('No ordering relation is defined for complex numbers')
}
Expand Down
23 changes: 19 additions & 4 deletions src/function/relational/smaller.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,20 @@ const name = 'smaller'
const dependencies = [
'typed',
'config',
'bignumber',
'matrix',
'DenseMatrix',
'concat',
'SparseMatrix'
]

export const createSmaller = /* #__PURE__ */ factory(name, dependencies, ({ typed, config, matrix, DenseMatrix, concat, SparseMatrix }) => {
function bigSmaller (config) {
return function (x, y) {
return x.lt(y) && !bigNearlyEqual(x, y, config.relTol, config.absTol)
}
}

export const createSmaller = /* #__PURE__ */ factory(name, dependencies, ({ typed, config, bignumber, matrix, DenseMatrix, concat, SparseMatrix }) => {
const matAlgo03xDSf = createMatAlgo03xDSf({ typed })
const matAlgo07xSSf = createMatAlgo07xSSf({ typed, SparseMatrix })
const matAlgo12xSfs = createMatAlgo12xSfs({ typed, DenseMatrix })
Expand Down Expand Up @@ -55,20 +62,28 @@ export const createSmaller = /* #__PURE__ */ factory(name, dependencies, ({ type
* @param {number | BigNumber | bigint | Fraction | boolean | Unit | string | Array | Matrix} y Second value to compare
* @return {boolean | Array | Matrix} Returns true when the x is smaller than y, else returns false
*/
const bignumSmaller = bigSmaller(config)

return typed(
name,
createSmallerNumber({ typed, config }),
{
'boolean, boolean': (x, y) => x < y,

'BigNumber, BigNumber': function (x, y) {
return x.lt(y) && !bigNearlyEqual(x, y, config.relTol, config.absTol)
},
'BigNumber, BigNumber': bignumSmaller,

'bigint, bigint': (x, y) => x < y,

'Fraction, Fraction': (x, y) => (x.compare(y) === -1),

'Fraction, BigNumber': function (x, y) {
return bignumSmaller(bignumber(x), y)
},

'BigNumber, Fraction': function (x, y) {
return bignumSmaller(x, bignumber(y))
},

'Complex, Complex': function (x, y) {
throw new TypeError('No ordering relation is defined for complex numbers')
}
Expand Down
2 changes: 1 addition & 1 deletion src/function/statistics/max.js
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ export const createMax = /* #__PURE__ */ factory(name, dependencies, ({ typed, c

deepForEach(array, function (value) {
try {
if (isNaN(value) && typeof value === 'number') {
if (typeof value === 'number' && isNaN(value)) {
res = NaN
} else if (res === undefined || larger(value, res)) {
res = value
Expand Down
2 changes: 1 addition & 1 deletion src/function/statistics/min.js
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ export const createMin = /* #__PURE__ */ factory(name, dependencies, ({ typed, c

deepForEach(array, function (value) {
try {
if (isNaN(value) && typeof value === 'number') {
if (typeof value === 'number' && isNaN(value)) {
min = NaN
} else if (min === undefined || smaller(value, min)) {
min = value
Expand Down
2 changes: 1 addition & 1 deletion src/function/string/print.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ export const createPrint = /* #__PURE__ */ factory(name, dependencies, ({ typed
* // the following outputs: 'The value of pi is 3.141592654'
* math.print('The value of pi is $pi', {pi: math.pi}, 10)
*
* // the following outputs: 'hello Mary! The date is 2013-03-23'
* // the following outputs: 'Hello Mary! The date is 2013-03-23'
* math.print('Hello $user.name! The date is $date', {
* user: {
* name: 'Mary',
Expand Down
5 changes: 5 additions & 0 deletions test/unit-tests/function/arithmetic/log.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,11 @@ describe('log', function () {
}
})

it('should return the log of a large bigint', function () {
const ten16 = 10000000000000000n
approxDeepEqual(log(ten16), 16 * log(10n))
})

it('should throw an error when used on a unit', function () {
assert.throws(function () { log(unit('5cm')) })
})
Expand Down
5 changes: 5 additions & 0 deletions test/unit-tests/function/arithmetic/log10.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,11 @@ describe('log10', function () {
approxDeepEqual(log10(complex(1, 0)), complex(0, 0))
})

it('should return the log base 10 of a large bigint', function () {
const ten16 = 10000000000000000n
assert.strictEqual(log10(ten16), 16)
})

it('should throw an error when used on a unit', function () {
assert.throws(function () { log10(unit('5cm')) })
})
Expand Down
5 changes: 5 additions & 0 deletions test/unit-tests/function/arithmetic/log2.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,11 @@ describe('log2', function () {
approxDeepEqual(log2(complex(1, 0)), complex(0, 0))
})

it('should return the log base two of a large bigint', function () {
const two70 = 2n ** 70n
assert.strictEqual(log2(two70), 70)
})

it('should throw an error when used on a unit', function () {
assert.throws(function () { log2(unit('5cm')) })
})
Expand Down
21 changes: 21 additions & 0 deletions test/unit-tests/function/probability/randomInt.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,27 @@ describe('randomInt', function () {
assertUniformDistributionInt(picked, -15, -5)
})

it('when called with no arguments, should flip a coin', function () {
const picked = Array.from({ length: 10000 }, () => randomInt())
assertUniformDistributionInt(picked, 0, 2)
})

it('should return a bigint given bigint limits', function () {
let picked = randomInt(1n, 7n)
assert.strictEqual(typeof picked, 'bigint')
assert(picked >= 1n)
assert(picked < 7n)
const wayBig = 10000000000000000n
picked = randomInt(wayBig, wayBig + 6n)
assert.strictEqual(typeof picked, 'bigint')
assert(picked >= wayBig)
assert(picked < wayBig + 6n)
picked = randomInt(1n, wayBig)
assert.strictEqual(typeof picked, 'bigint')
assert(picked >= 1n)
assert(picked < wayBig)
})

it('should pick uniformly distributed random array, with elements in [min, max)', function () {
const picked = []
const matrices = []
Expand Down
20 changes: 13 additions & 7 deletions test/unit-tests/function/relational/larger.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import assert from 'assert'
import math from '../../../../src/defaultInstance.js'
const bignumber = math.bignumber
const complex = math.complex
const fraction = math.fraction
const matrix = math.matrix
const sparse = math.sparse
const unit = math.unit
Expand Down Expand Up @@ -94,19 +95,24 @@ describe('larger', function () {
})

it('should compare two fractions', function () {
assert.strictEqual(larger(math.fraction(3), math.fraction(2)).valueOf(), true)
assert.strictEqual(larger(math.fraction(2), math.fraction(3)).valueOf(), false)
assert.strictEqual(larger(math.fraction(3), math.fraction(3)).valueOf(), false)
assert.strictEqual(larger(fraction(3), fraction(2)).valueOf(), true)
assert.strictEqual(larger(fraction(2), fraction(3)).valueOf(), false)
assert.strictEqual(larger(fraction(3), fraction(3)).valueOf(), false)
})

it('should compare mixed fractions and numbers', function () {
assert.strictEqual(larger(1, math.fraction(1, 3)), true)
assert.strictEqual(larger(math.fraction(2), 2), false)
assert.strictEqual(larger(1, fraction(1, 3)), true)
assert.strictEqual(larger(fraction(2), 2), false)
})

it('should compare mixed fractions and bigints', function () {
assert.strictEqual(larger(1n, math.fraction(1, 3)), true)
assert.strictEqual(larger(math.fraction(2), 2n), false)
assert.strictEqual(larger(1n, fraction(1, 3)), true)
assert.strictEqual(larger(fraction(2), 2n), false)
})

it('should compare mixed fractions and bignumbers', function () {
assert.strictEqual(larger(bignumber(1), fraction(1, 3)), true)
assert.strictEqual(larger(fraction(2), bignumber(2)), false)
})

it('should add two measures of the same unit', function () {
Expand Down
Loading