naruyoko / omeganum.js Goto Github PK
View Code? Open in Web Editor NEWA huge number library holding up to 10{1000}9e15. A basement for planned {10,x,1,2}.
Home Page: https://naruyoko.github.io/OmegaNum.js/index.html
License: MIT License
A huge number library holding up to 10{1000}9e15. A basement for planned {10,x,1,2}.
Home Page: https://naruyoko.github.io/OmegaNum.js/index.html
License: MIT License
Heya, so I don't know if this is in your control, but calculations around Number.MAX_SAFE_INTEGER (about 9e15) are kinda inaccurate, which sucks for being such a relatively low value.
For example, if I put in the console: OmegaNum.div(9.4e13, 9.4e14), it returns 0.1 (as it should)
but if I put in OmegaNum.div(9.4e14, 9.4e15), it returns 0 because it crosses the threshold of Number.MAX_SAFE_INTEGER (presumably when the array gets pushed to two values).
Hopefully this could be fixed, as it does cause a few issues in calculations for an incremental game i'm making using your library.
Thanks,
Jacorb
In my calculation, [1,0,1] = 10^^1=10 and [1,0,0,1]=10^^^1=10
But OmegaNum([1,0,1]) -> 10000000000, OmegaNum([1,0,0,1]) -> [10000000000,9]
What?
You used input1 instead of input in like 5 places
Run the following with profiler:
for(var i=0;i<10000;i++)OmegaNum.hyper(Math.random()*10+3|0)(Math.random()*100+3,Math.random()*100+3);
On my configuration, it ran for 15975ms, taking 3529.7ms in fromString
, 3153.3ms in OmegaNum
, and 3000.6ms in standardize
(self time). The same functions appear by profiling True Infinity Beta. This is quite bad. Of these 3, I think fromString
and standardize
can be rewritten to perform much better. Maybe it is time to work on it.
OmegaNum.tetr(1.441,Infinity) is 2.427380218613476
but OmegaNum.tetr(1.441,1e100) is 10^^1e100
the correct result is 2.427380218613476
Once you're around 'layer 9e15' (in break_eternity.js terms, 10^ 9e15 times and then mag), the only meaningful operators (because they increase/decrease layer by more than 1 at a time) are hyper-4 (tetrate, slog, sroot, iterated_log) and stronger operators (pentate, hexate, hyper_n, etc). Notably, something like tetrate for a number so large basically just increases layer by whatever number you're iterating to - so at this point the actual value of mag is meaningless (it doesn't give enough information to determine where in between all of the layers).
At that point, it would make sense to ignore mag and split layer into layer_2 and layer_1, and compute all numbers as 10^^10^^10^^ ... (layer_2 times) 10^10^10^10^ ... (layer_1 times) 1 (or 10).
Then when you hit 9e15 in layer_2, by a similar rationale, you could ignore layer_1 and split layer_2 into layer_3 and layer_2.
Or in other words, store the following numbers:
sign, layer_increment, higher_layer, lower_layer
When layer_increment is 0, it reduces to the case of break_eternity.js : sign*10^10^10^ (higher_layer times) lower_layer.
When layer_increment is 1, it's 10^^10^^10^^ (higher_layer times) 10^10^10^10^ (lower_layer times) 1 (or 10).
When layer_increment is 2, it's the same but with an extra ^ on both sides... And so on up until layer_increment 9e15. This would get around your 'I'm restricted by how big of an array I'm willing to lug about' technical constraint and seems like a logical step to take.
(TODO: And then you split layer_increment into layer_layer_increment, higher_layer_increment, lower_layer_increment...? When does the madness end? When you beg for it to stop!)
(Also, as a side note - the reason why I deleted break_break_infinity.js is both to reduce code bloat and because it's redundant. break_infinity.js handles < 1e9e15 cases much better, and break_eternity.js handles everything higher. I've come to realize that at the boundaries of a numerical library, either you don't care about the precision loss (and let's face it, you don't, it's an incremental game and you'll be skipping up exponents then layers then layers layers in the thousands at a time by this point) or you need a stronger numerical library, not a hack job that only gets you slightly further. There's no break_break_eternity.js because if you're at 9e15 layers, you're going up multiple layers at a time to get there and don't care about the precision loss, OR you don't get there at all and want the efficiency more than the precision.)
new OmegaNum("0.000002").toString();
OmegaNum.js:1036 [OmegaNumError] Malformed input: 0.000002
Q.fromString @ OmegaNum.js:1036
OmegaNum @ OmegaNum.js:1266
(anonymous) @ VM1062:1
"NaN"
On the other hand, OmegaNum(0.000002) gives the expected result:
new OmegaNum(0.000002).toString();
"0.000002"
Currently (release 0.5.7), attempting to convert a BigInt value to OmegaNum will return either NaN
if the BigInt is being passed in directly or Infinity
if the BigInt (whose value is bigger than 21024) is converted to a string which is then passed into the OmegaNum constructor.
new OmegaNum(1234n).toString()
'NaN'
new OmegaNum(2n**1234n).toString()
'NaN'
new OmegaNum(String(1234n)).toString()
'1234'
new OmegaNum(String(2n**1234n)).toString()
'Infinity'
The expected output should be 1234 for the 1234n
test case and approximately 2.958112e371 for the 2n**1234n
test case.
OmegaNum.add(0, 1e16).toString();
"NaN"
I'm too lazy to fix it rn
Expected result
OmegaNum(-10)
"-10"
OmegaNum("-10")
"-10"
OmegaNum("-ee20")
"-e1e20"
OmegaNum("-10^^100")
"-(10^)^98 10000000000"
Actual result:
OmegaNum(-10)
"-10"
OmegaNum("-10")
"10"
OmegaNum("-ee20")
"e1e20"
OmegaNum("-10^^100")
"(10^)^98 10000000000"
Checked on https://naruyoko.github.io/OmegaNum.js/index.html.
Using OmegaNum.hyper(900)(10, 10), for example freezes everything. It begins to take a noticeable amount of time around the 100th hyperoperator, and gets worse as it goes. You need to take some shortcuts to make this library actually function up to the 1000th hyperoperator, or at least put some warnings.
This evaluation doesn't warn and/or give Infinity because of the error occurred before the evaluation is complete.
OmegaNum("10{1000}10")
OmegaNum.js:1256 Uncaught TypeError: arrows.add is not a function
at Q.fromString (OmegaNum.js:1256:87)
at new OmegaNum (OmegaNum.js:1465:23)
at OmegaNum (OmegaNum.js:1445:44)
at <anonymous>:1:1
Other methods work fine as since
OmegaNum.arrow(10,1000,10).eq(Infinity)
OmegaNum.js:877 Number too large to reasonably handle it: tried to 1002-ate.
(anonymous) @ OmegaNum.js:877
Q.arrow @ OmegaNum.js:919
(anonymous) @ VM323:1
true
OmegaNum('10^^10') == OmegaNum('10') for some reason.
OmegaNum.pow("eee15", "eee16").toString()
"1"
Decimal.pow("eee15", "eee16").toString()
"eeee16"
During creating docs, I found the following bugs:
ceil
- Does nothing.cbrt
- Very wrong answer. Look at root
.floor
- Does nothing.hyper
- Wrong offset: should have -2
, instead of +2
.modulo
- Very wrong answer.root
- Very wrong answer.round
- Does nothing.sqrt
- Very wrong answer. Look at root
.new OmegaNum("10^^100") == 1, not [100,0,1]
new OmegaNum("10^^101") == 10, not [101,0,1]
new OmegaNum("10^^1000") == 1, not [1000,0,1]
new OmegaNum("10^^1001") == 10, not [1001,0,1]
new OmegaNum("10^^10000") == 1, not [10000,0,1]
See #25 .
What?
> OmegaNum(1.4447).tetr(101)+''
< '2.6717465674555796'
> OmegaNum(1.4447).pow(OmegaNum(1.4447).tetr(100))+''
< '2.672301459237309'
I expect that those two have similar result, but the former seems to be 1.4447^^100 instead of 1.4447^^101.
OmegaNum.add(1e15, -1e15).toString()
"-0"
OmegaNum.add(1e16, -1e16).toString()
"-Infinity"
break_eternity.js special cases this and you probably should too, since it holds true no matter how massive your number is. https://github.com/Patashu/break_eternity.js/blob/master/break_eternity.js#L1198
EDIT: Actually, the root cause might be an off by one error when computing layer 1 or higher negative numbers vs computing positive numbers:
new OmegaNum("-1e16").array[0]
16
new OmegaNum("-1e16").array[1]
2
new OmegaNum("1e16").array[0]
16
new OmegaNum("1e16").array[1]
1
Obviously both should be layer 1.
Actually, this bug might be independent, because even if we do a neg instead of construct from string:
OmegaNum.add("e16", new OmegaNum("e16").neg()).toString()
"-Infinity"
yet:
new OmegaNum("e16").neg().array[0]
16
new OmegaNum("e16").neg().array[1]
1
new OmegaNum("e16").array[0]
16
new OmegaNum("e16").array[1]
1
OmegaNum.div("ee16", "ee15").toString()
"Infinity"
OmegaNum.div("eee15", "eee16").toString()
"eee16"
Decimal.div("ee16", "ee15").toString()
"ee15.954242509439325"
Decimal.div("eee15", "eee16").toString()
"0"
OmegaNum.mul("ee99999999999999", "eee15").toString()
"e1e1000000000000000"
OmegaNum.mul("ee999999999999999", "eee15").toString()
OmegaNum.html:238 Uncaught TypeError: x.div(...).max is not a function
at OmegaNum.P.plus.P.add (OmegaNum.html:238)
at OmegaNum.P.times.P.mul (OmegaNum.html:289)
at Function.Q.times.Q.mul (OmegaNum.html:292)
at <anonymous>:1:10
OmegaNum.mul("eee15", "eee15").toString()
"e1.7782794100389228e1000000000000000"
Decimal.mul("ee999999999999999", "eee15").toString()
"ee1000000000000000"
OmegaNum.mul("eee15", "eee15").toString()
"e1.7782794100389228e1000000000000000"
It seems like the bug is in div specifically:
OmegaNum.div("e999999999999999", "ee15")
ฦ (){
return OmegaNum(this);
}
new OmegaNum("eee15").toString()
"e1e1000000000000000"
new OmegaNum("eee15").ln().pow(Math.E).toString()
"1e2718281828459044"
vs
new Decimal("eee15").toString()
"ee1000000000000000"
new Decimal("eee15").ln().exp().toString()
"ee1000000000000000"
new OmegaNum("eee7").ln().toString()
OmegaNum.html:299 Uncaught RangeError: Maximum call stack size exceeded
at OmegaNum.P.divide.P.div (OmegaNum.html:299)
at OmegaNum.P.plus.P.add (OmegaNum.html:238)
at OmegaNum.P.minus.P.sub (OmegaNum.html:259)
at OmegaNum.P.divide.P.div (OmegaNum.html:302)
at OmegaNum.P.plus.P.add (OmegaNum.html:238)
at OmegaNum.P.minus.P.sub (OmegaNum.html:259)
at OmegaNum.P.divide.P.div (OmegaNum.html:302)
at OmegaNum.P.plus.P.add (OmegaNum.html:238)
at OmegaNum.P.minus.P.sub (OmegaNum.html:259)
at OmegaNum.P.divide.P.div (OmegaNum.html:302)
new OmegaNum("ee7").ln().toString()
OmegaNum.html:607 Uncaught RangeError: Maximum call stack size exceeded
at String.search (<anonymous>)
at new OmegaNum (OmegaNum.html:607)
at OmegaNum (OmegaNum.html:577)
at OmegaNum.P.compareTo.P.cmp (OmegaNum.html:123)
at OmegaNum.P.greaterThan.P.gt (OmegaNum.html:138)
at OmegaNum.P.divide.P.div (OmegaNum.html:300)
at OmegaNum.P.plus.P.add (OmegaNum.html:238)
at OmegaNum.P.minus.P.sub (OmegaNum.html:259)
at OmegaNum.P.divide.P.div (OmegaNum.html:302)
at OmegaNum.P.minus.P.sub (OmegaNum.html:260)
OmegaNum(10).tetr(1e16).tetr(1e16).toString()
"10^^1e16"
OmegaNum(10).tetr(1e17).tetr(1e16).toString()
"10^^1e16"
OmegaNum(10).arrow(3)(1e16).arrow(3)(1e16).toString()
"10^^^1e16"
OmegaNum(10).arrow(3)(1e17).arrow(3)(1e16).toString()
"10^^^1e16"
I put them in one issue because their points might be identical. You might forget when the "base number" affects result of a hyper-operation. If the base number is large enough, it affects the "top layer" value and thus affects the amount of "layers". For instance, (10^^1e16)^^1e16 = (10^^1e16)^(10^^1e16)^...^(10^^1e16)^(10^^1e16) (1e16-1 single arrows) > 10^10^...10^(10^^1e16) = 10^10^...10^10^10^...10^10 (2e16-1 10's in total).
The correct answer of those four should be around 10^^2e16, 10^^1.1e17, 10^^^2e16, 10^^^1.1e17, respectively.
like in the title, is it possible to get a .d.ts file for this?
E100#^#100
OmegaNum(3).tetr(OmegaNum(3).pow(1000).div(OmegaNum(3).pow(990))).toString()
"NaN"
OmegaNum(3).arrow(5)(OmegaNum(3).pow(1000).div(OmegaNum(3).pow(990))).toString()
"NaN"
new OmegaNum(-1).cmp(new OmegaNum(-2))
-1
(should be 1 since -1 > -2)
to fix this, you just have to multiply the return value by the sign if the signs are different, e.g. https://github.com/Patashu/break_eternity.js/blob/master/break_eternity.js#L1456
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.