import Decimal from "break_infinity.js" ; import { Notation } from "../notation" ; import { toSuperscript } from "../utils" ; const MAX_INT = Number . MAX_SAFE_INTEGER ; const MAX_INT_DECIMAL = new Decimal ( MAX_INT ) ; const MAX_INT_LOG_10 = Math . log10 ( MAX_INT ) ; const MAX_FACTOR = 10000 ; export class PrecisePrimeNotation extends Notation { public get name ( ) : string { return "Precise Prime" ; } public get infinite ( ) : string { return "Primefinity?" ; } public formatUnder1000 ( value ) { return this . primify ( new Decimal ( value ) ) ; } public formatDecimal ( value ) { return this . primify ( value ) ; } private primify ( value ) { if ( value . lte ( MAX_INT_DECIMAL ) ) { const floored = Math . floor ( value . toNumber ( ) ) ; if ( floored === 0 ) { return "0" ; } if ( floored === 1 ) { return "1" ; } return this . formatFromList ( this . primesFromInt ( floored ) ) ; } let exp = value . log10 ( ) / MAX_INT_LOG_10 ; let base = MAX_INT ** ( exp / Math . ceil ( exp ) ) ; if ( exp <= MAX_INT ) { return this . formatPowerTower ( [ Math . round ( base ) , Math . ceil ( exp ) ] ) ; } const exp2 = Math . log10 ( exp ) / Math . log10 ( MAX_INT ) ; const exp2Ceil = Math . ceil ( exp2 ) ; exp = MAX_INT ** ( exp2 / exp2Ceil ) ; base = MAX_INT ** ( exp / Math . ceil ( exp ) ) ; return this . formatPowerTower ( [ Math . round ( base ) , Math . ceil ( exp ) , exp2Ceil ] ) ; } private maybeParenthesize ( x , b ) { return b ? `(${ x })` : x ; } private formatPowerTower ( exps ) { const factorizations = exps . map ( ( x ) => this . primesFromInt ( x ) ) ; const superscriptLastExponent = factorizations [ exps . length - 1 ] . length === 1 ; const parenthesize = factorizations . map ( ( x , i ) => x [ 0 ] !== x [ x . length - 1 ] || i === exps . length - 2 && x . length > 1 && superscriptLastExponent ) ; const formattedExps = factorizations . map ( ( x , i ) => this . maybeParenthesize ( i === exps . length - 1 && superscriptLastExponent ? toSuperscript ( x [ 0 ] ) : this . formatFromList ( x ) , parenthesize [ i ] ) ) ; if ( superscriptLastExponent ) { const superscript = formattedExps . pop ( ) ; formattedExps [ exps . length - 2 ] += superscript ; } return formattedExps . join ( "^" ) ; } private formatFromList ( factors ) { const out = [ ] ; let last = 0 ; let count = 0 ; for ( const i of factors ) { if ( i === last ) { count ++ ; } else { if ( last > 0 ) { if ( count > 1 ) { out . push ( `${ last }${ toSuperscript ( count ) }` ) ; } else { out . push ( last ) ; } } last = i ; count = 1 ; } } if ( count > 1 ) { out . push ( `${ last }${ toSuperscript ( count ) }` ) ; } else { out . push ( last ) ; } return out . join ( "\u00D7" ) ; } private primesFromInt ( num ) { let n = num ; const l = [ ] ; for ( const k of [ 2 , 3 ] ) { for ( ; n % k === 0 ; n /= k ) { l . push ( k ) ; } } const lim = Math . min ( MAX_FACTOR , Math . floor ( Math . sqrt ( n ) ) ) ; for ( let a = 5 ; a <= lim && a < n ; ) { for ( ; n % a === 0 ; n /= a ) { l . push ( a ) ; } a += 2 ; for ( ; n % a === 0 ; n /= a ) { l . push ( a ) ; } a += 4 ; } if ( n > 1 ) { l . push ( n ) ; } return l ; } }