Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/feature-stringify'
Browse files Browse the repository at this point in the history
* origin/feature-stringify:
  Test with bases other than 10.
  Finish implementation of stringify.
  Update dependency @aureooms/js-integer to v6
  Inital draft for stringify.
  🔍 test: Extract fixtures.
  • Loading branch information
make-github-pseudonymous-again committed May 4, 2020
2 parents 6b26c0e + 7ef0307 commit 983a4d3
Show file tree
Hide file tree
Showing 9 changed files with 238 additions and 9 deletions.
6 changes: 5 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,13 @@
"bugs": {
"url": "https://github.com/aureooms/js-rational/issues"
},
"dependencies": {},
"dependencies": {
"@aureooms/js-itertools": "^4.0.0"
},
"devDependencies": {
"@aureooms/js-integer": "6.0.0",
"@aureooms/js-number": "^3.1.0",
"@aureooms/js-prime": "^4.0.0",
"@babel/cli": "7.8.4",
"@babel/core": "7.9.6",
"@babel/polyfill": "7.8.7",
Expand Down
19 changes: 19 additions & 0 deletions src/_stringify_digits.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
export function _stringify_digits ( str , base , { sign , left , transient , repetend } ) {

const toStr = x => str(x, base);

let repr = '' ;

if (sign < 0) repr += '-' ;

repr += toStr(left) ;

if (transient.length || repetend.length) repr += '.' ;
repr += transient.map(toStr).join('') ;

if (repetend.length) repr += '|' ;
repr += repetend.map(toStr).join('') ;

return repr ;

}
41 changes: 41 additions & 0 deletions src/decimals.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
// TODO instead allocate enough space M < log_2(d) + d
// for transient + repetend by multiplying x by b**M and do a single division ?
// That may be too much space in most cases. Though necessary when d is prime.

export function _decimals ( { b , eq , muln , divmod } ) {

return function* ( d , n , hasrepetend , x ) {

// Computes the length of the repetend of x/d (1 <= x < d) in base b
// with transient part of size n.

while ( n-- ) {

x = muln(x, b) ;
const [q, r] = divmod(x, d) ;
yield q ;
x = r ;

}

if ( !hasrepetend ) return ;

const first = x ;

x = muln(x, b) ;
const [q, r] = divmod(x, d) ;
yield q ;
x = r ;

while (!eq(first, x)) {

x = muln(x, b) ;
const [q, r] = divmod(x, d) ;
yield q ;
x = r ;

}

} ;

}
28 changes: 28 additions & 0 deletions src/digits.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { take } from '@aureooms/js-itertools' ;
import { _decimals } from './decimals' ;
import { _transient } from './transient' ;

export function _digits ( { b , bfactors , jz , gt1 , eq , muln , divmodn , divmod , egcd , sgn , abs } ) {

const tr = _transient( { bfactors , jz , gt1 , divmodn } ) ;
const dec = _decimals( { b , eq , muln , divmod } ) ;

return function ( x , d ) {

const [ left , r ] = divmod(abs(x), d) ;

const { u , v } = egcd(d, r) ;

const [ transient_length , has_repetend ] = tr( v ) ;

const decimals = dec(v, transient_length, has_repetend , u) ;

const transient = [ ...take(decimals, transient_length) ] ;

const repetend = [ ...decimals ] ;

return { sign: sgn(x) , left , transient , repetend } ;

}

}
2 changes: 2 additions & 0 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,5 @@ export * from './pow' ;
export * from './cmp' ;
export * from './cmp_no_bounds' ;
export * from './simplify' ;
export * from './digits' ;
export * from './_stringify_digits' ;
38 changes: 38 additions & 0 deletions src/transient.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
// credits https://github.com/aureooms-research/repeating-decimal

export function _transient ( { bfactors , jz , gt1 , divmodn } ) {

return function ( d ) {

// Computes the length of the non repeating part in x / d
// ( for any 1 <= x < d with x and d co-prime ) decimals in
// base b whose prime factors are given. Returns tuple ( n , hasrepetend )
// where n is the length of the non repeating part and hasrepetend
// determines if 1 / d repeats or not.

let n = 0 ;

for ( const f of bfactors ) {

let m = 0 ;

while ( true ) {

const [ q , r ] = divmodn(d, f) ;

if (!jz(r)) break ;

++m ;
d = q ;

}

n = Math.max(n, m) ;

}

return [ n , gt1(d) ] ;

} ;

}
30 changes: 27 additions & 3 deletions test/src/_fixtures.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,34 +8,47 @@ export const ALU = [
add : (a, b) => a.add(b),
sub : (a, b) => a.sub(b),
mul : (a, b) => a.mul(b),
muln : (a, b) => a.mul(b),
div : (a, b) => a.div(b),
reg : x => int(x),
str : x => x.toString(),
jz : x => x.eq(0),
lt0 : x => x.lt(0),
gt1 : x => x.gt(1),
cmp : (a,b) => a.cmp(b),
eq : (a,b) => a.eq(b),
neg : x => x.neg(),
sgn : x => x.cmp(0),
abs : x => x.abs(),
divmod : (a,b) => [a.div(b), a.mod(b)],
divmodn : (a,b) => [a.div(b), a.mod(b)],
pown : (x,n) => x.pow(n),
},
{
name : 'bn.js',
add : (a, b) => a.add(b),
sub : (a, b) => a.sub(b),
mul : (a, b) => a.mul(b),
muln : (a, b) => a.muln(b),
div : (a, b) => a.div(b),
reg : x => new BN(x),
str : x => x.toString(),
str : (x, base) => x.toString(base),
jz : x => x.eqn(0),
lt0 : x => x.ltn(0),
gt1 : x => x.gtn(1),
cmp : (a,b) => a.cmp(b),
eq : (a,b) => a.eq(b),
sgn : x => x.cmpn(0),
abs : x => x.abs(),
neg : x => x.neg(),
divmod : (a,b) => {
const { div , mod } = a.divmod(b) ;
return [div, mod] ;
} ,
divmodn : (a,b) => {
const { div , mod } = a.divmod(new BN(b)) ;
return [div, mod] ;
} ,
egcd : (a,b) => {
const gcd = a.gcd(b) ;
return { u: b.div(gcd), v: a.div(gcd) } ;
Expand All @@ -47,16 +60,27 @@ export const ALU = [
add : (a, b) => a.add(b),
sub : (a, b) => a.sub(b),
mul : (a, b) => a.mul(b),
muln : (a, b) => a.muln(b),
div : (a, b) => a.div(b),
reg : x => ZZ.from(x),
str : x => x.toString(),
str : (x, base) => x.toString(base),
jz : x => x.iszero(),
lt0 : x => x.sign() < 0,
gt1 : x => x.gtn(1),
cmp : (a,b) => a.cmp(b),
eq : (a,b) => a.eq(b),
sgn : x => x.sign(),
abs : x => x.abs(),
neg : x => x.opposite(),
divmod : (a,b) => a.divmod(b),
egcd : (a,b) => a.egcd(b),
divmodn : (a,b) => a.divmodn(b),
egcd : (a,b) => {
const { u , v } = a.egcd(b) ;
return {
u: u.iabs(),
v: v.iabs(),
} ;
},
pown : (x,n) => x.pown(n),
}
];
Expand Down
58 changes: 53 additions & 5 deletions test/src/core.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,18 @@
import test from 'ava';
import { _add , _sub , _mul , _div , _pow , _cmp , _cmp_no_bounds , _simplify } from '../../src';
import { __factorize__ } from '@aureooms/js-prime' ;
import { $2, iadd1, eq0, gt1, divmod } from "@aureooms/js-number" ;
import {
_add , _sub , _mul , _div , _pow ,
_cmp , _cmp_no_bounds ,
_simplify , _digits , _stringify_digits
} from '../../src';

const GOOGOL = '10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' ;

const factorize = __factorize__( $2, iadd1, eq0, gt1, divmod ) ;

const ufactors = n => new Set(factorize(n)) ;

import { ALU } from './_fixtures' ;

function binary ( t , alu , [ [ _x , _y , factory ] , a , b , c , d , e ] ) {
Expand Down Expand Up @@ -51,14 +61,12 @@ function unary ( t , alu , [ [ _x , _y , factory ] , a , b , e ] ) {

const apply = factory( alu );

const repr = x => `${alu.str(x[0])}/${alu.str(x[1])}` ;

const _a = alu.reg(a);
const _b = alu.reg(b);

const z = apply( _a , _b ) ;

t.is(e, repr(z));
t.is(e, z);

}

Expand All @@ -72,7 +80,24 @@ const mul = [ 'mul' , '*' , [ _mul ] , binary ] ;
const div = [ 'div' , '/' , [ _div ] , binary ] ;
const pow = [ 'pow' , '^' , [ _pow ] , binary_n ] ;
const cmp = [ 'cmp' , '~' , [ _cmp , _cmp_no_bounds ] , binary ] ;
const simplify = [ 'simplify' , '=' , [ _simplify ] , unary , alu => alu.egcd ] ;
const simplify = [ 'simplify' , '=' , [
alu => {
const repr = x => `${alu.str(x[0])}/${alu.str(x[1])}` ;
const simp = _simplify(alu) ;
return (a,b) => repr(simp(a,b)) ;
}
] , unary , alu => alu.egcd ] ;


const stringify_n = b => alu => {
const bfactors = ufactors( b ) ;
const digits = _digits({ b , bfactors , ...alu }) ;
return ( x , d ) => _stringify_digits( alu.str , b , digits(x, d) ) ;
} ;

const stringify_10 = [ 'stringify_10' , '=' , [ stringify_n(10) ] , unary , alu => alu.egcd ] ;
const stringify_2 = [ 'stringify_2' , '=' , [ stringify_n(2) ] , unary , alu => alu.egcd ] ;
const stringify_19 = [ 'stringify_19' , '=' , [ stringify_n(19) ] , unary , alu => alu.egcd ] ;

const PARAMS = [

Expand Down Expand Up @@ -166,6 +191,29 @@ const PARAMS = [
[ simplify , '-170141183460469231731687303715884105729' , '3' , '-56713727820156410577229101238628035243/1' ] ,
[ simplify , '-3' , '170141183460469231731687303715884105729' , '-1/56713727820156410577229101238628035243' ] ,

[ stringify_10 , '1' , '7' , '0.|142857' ] ,
[ stringify_10 , '-4' , '8' , '-0.5' ] ,
[ stringify_10 , '7' , '14' , '0.5' ] ,
[ stringify_10 , '0' , '43' , '0' ] ,
[ stringify_10 , '86' , '43' , '2' ] ,
[ stringify_10 , '2' , '46' , '0.|0434782608695652173913' ] ,
[ stringify_10 , '1' , '46' , '0.0|2173913043478260869565' ] ,
[ stringify_10 , '1' , '14' , '0.0|714285'] ,
[ stringify_10 , '1' , '45' , '0.0|2' ] ,
[ stringify_10 , '733' , '750' , '0.977|3' ] ,
[ stringify_10 , '22' , '7' , '3.|142857' ] ,
[ stringify_10 , '355' , '113' , '3.|1415929203539823008849557522123893805309734513274336283185840707964601769911504424778761061946902654867256637168' ] ,
[ stringify_10 , '7775' , '2260' , '3.44|0265486725663716814159292035398230088495575221238938053097345132743362831858407079646017699115044247787610619469' ] ,

[ stringify_2 , '-4' , '8' , '-0.1' ] ,
[ stringify_2 , '7' , '14' , '0.1' ] ,
// printf -- "scale=10;obase=2;1/7\n" | bc --mathlib
[ stringify_2 , '1' , '7' , '0.|001' ] ,

[ stringify_19 , '1' , '2' , '0.|9' ] , // HAHA

[ stringify_19 , '14' , '13', '1.|18ebd2ha475g'] , // HOHO

] ;

for (const alu of ALU)
Expand Down
25 changes: 25 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,13 @@
# yarn lockfile v1


"@aureooms/js-collections-deque@^4.0.0":
version "4.0.0"
resolved "https://registry.yarnpkg.com/@aureooms/js-collections-deque/-/js-collections-deque-4.0.0.tgz#cb6ff3070f4413023622db817da261f91e42aef0"
integrity sha512-+dI0PSkshl0vKmeyfzWM5Xtfopu4XYIrlqKKq3emjyuCi1DCO9SaPIgKblMDjl9WttmJhTYsunNyPYula5woAw==
dependencies:
"@aureooms/js-error" "^4.0.0"

"@aureooms/js-error@^4.0.0":
version "4.0.0"
resolved "https://registry.yarnpkg.com/@aureooms/js-error/-/js-error-4.0.0.tgz#cea0a145f5290f443911b3d1890d7254a18eeb9b"
Expand All @@ -20,6 +27,24 @@
"@aureooms/js-error" "^4.0.0"
"@aureooms/js-integer-big-endian" "^8.0.0"

"@aureooms/js-itertools@^4.0.0":
version "4.0.0"
resolved "https://registry.yarnpkg.com/@aureooms/js-itertools/-/js-itertools-4.0.0.tgz#2f7247b4a89202606bb54a731753590625b4b185"
integrity sha512-QhCT+RDUbWPL7h3RA7LcXdC1IQdR3Bfl0Re0ClDxem7DUnRbHuL4Nlwgo3UoqaRBE8OI4RpBw+hXVVqVg14J9Q==
dependencies:
"@aureooms/js-collections-deque" "^4.0.0"
"@aureooms/js-error" "^4.0.0"

"@aureooms/js-number@^3.1.0":
version "3.1.0"
resolved "https://registry.yarnpkg.com/@aureooms/js-number/-/js-number-3.1.0.tgz#460155de73084d25e648680309d9d1d941e3df89"
integrity sha512-Z+Dmml9TjuhnxaOIWu8OZ3iYFPJsLJNynv1qgwYTO7dsZznMPge1ME5VmFeTNNsZSg9DtavXVyfYla+XxWXHRg==

"@aureooms/js-prime@^4.0.0":
version "4.0.0"
resolved "https://registry.yarnpkg.com/@aureooms/js-prime/-/js-prime-4.0.0.tgz#95ceb59a67ca009afb76b3045daab174b40f24f2"
integrity sha512-U5Hji39rqTK+ktMTQZvSx/AhX09wLj3ESQPl7fep/ip/FMskeaHtCK8zAQ6QcneLDBCHOMV0x6C9CckWqiCzag==

"@babel/cli@7.8.4":
version "7.8.4"
resolved "https://registry.yarnpkg.com/@babel/cli/-/cli-7.8.4.tgz#505fb053721a98777b2b175323ea4f090b7d3c1c"
Expand Down

0 comments on commit 983a4d3

Please sign in to comment.