Working with transfinite ordinals in JavaScript - javascript

I'm attempting to program a transfinite ordinal calculator in JavaScript. In other words, find a way to process ordinal arithmetic in js.
I'm planning on using ES6's classes, with some form of constructor, and methods for processing comparisons of terms and operations such as addition or multiplication over the set of ordinals. The problem is that I don't know where to start. I need firstly a way to store ordinals in an instance of an Ordinal class, and a way of comparing to Ordinals. After that point everything should be smooth sailing.
If anyone could provide any insight into how I might approach this, I'd greatly appreciate it.

In the last 6 months I've found several methods of storing ordinals, these include:
Cantor Normal Form as an array
Extended Cantor Normal Form as nested arrays of pairs
An ordinal notation (known as TAN) developed by a member of the Googology community
Veblen's Hierarchy of Fixed Points
An ordinal collapsing function
Disclaimer: I use a common convention when writing out ordinals. I use w to represent omega, the least transfinite ordinal; e to represent the epsilon numbers (fixed points of a -> w^a) or the function enumerating them; similarly, in the case of Veblen's Hierarchy I'll use phi to denote such for ordinal collapsing functions I'll use psi. When explaining how operations work I'll use this to denote the first operand and other to denote the second.
Cantor Normal Form expresses ordinals as the sum of terms in the form w^b * a and therefore has a limit of w^w, intuitively it can be expressed as an array, where the i'th element of the term represents the a in the term w^i * a, e.g. the array [4, 5, 6] represents the ordinal w^2*6 + w*5 + 4. Adding is simple enough. Based on the principle that 1 + w = w, w + w^2 = w^2 and so on, we can fill the array with 0s up to the other.length - 1'th element and then add the elements in other to their corresponding elements in this. Multiplication is more tricky. If other contains multiple non-zero elements, we can use the distributive law (which doesn't apply the other way) and return the sum of this multiplied by each of other's terms. Otherwise, if this has multiple non-zero elements, if other is finite (other.length == 1) then multiply the most significant term of this by other and return other. In the final case ignore all but the most significant term of this and multiply by other. And if both operands have only one term then shift a bunch of 0s into this (specifically other.length - 1) and return this. Exponentiation is trivial then as other must be finite otherwise the result would surpass the range of this method, and can just be done by iterating multiplication, because I'm lazy and can do better later.
Extended Cantor Normal Form is similar, though the exponents for each term can also be ordinals, which complicates things, though extends the limit of this to e0 (the least fixed point of a -> w^a. We can store ordinals as an array of pairs. The first element of the pair can be coefficient of the terms and the second element is the exponent, represented by another array of pairs. The first thing that needs to be addressed in this form would be normalization. Firstly you'd need to remove all terms which are 0, then iterate through the array and keep track of the largest exponent, if you encounter an element with a lower exponent that the current highest you'd splice it out of the array. Once this is done you check for terms with the same exponent and add the coefficient of the other to one, removing the other. The array will then be normalized (there's probably a more efficient way to do this, leave a comment). Addition follows then become trivial. Simply concatenate the arrays of other and this and normalize. Multiplication is similar to before. If other.length > 1 then we can use the distributive law (which doesn't apply the other way) and return the sum of this multiplied by each of other's terms. Otherwise, if this has multiple terms, if other is finite then multiply the most significant term of this by other and return other. In the final case ignore all but the most significant term of this and multiply by other. Then simply add the exponent of other's only term to this's only term and return this. Exponentiation is no longer trivial, but isn't difficult. Firstly, remove all but the most significant term from this, then multiply the exponent by other. Done.
A member of the Googology* community, TGR, created TAN as an extremely powerful array notation for generating large numbers, though it was essentially the fast growing hierarchy with an array-like ordinal notation. The ordinal notation isn't exactly well defined, though it can be understood well enough. TAN. Note that I would only code the arrays without 'separators' for simplicity. Ordinals can be stored as arrays where elements are either arrays or integers. Normalization can be done by popping 0s off the end of the array and checking if any elements have greater value than the outer array (without that element), if they are, then remove the outer array. This is as each of the elements of the arrays enumerates as a function of the form a + b, a * w^b, e, phi_2, phi_3 etc, and such an array just as [0, 0, [0, 0, 0, 1]] would be e(psi_2(0)) which is simply equal to phi_2(0) as phi_2(0) is a fixed point of the function enumerating the epsilon numbers. Adding in this notation is simple, take the first element of the this, and then the first element of that, and so on until we get to an integer, then if other is finite simply add it on, if other is transfinite then replace the integer in this. Multiplying is similar, though you instead increase the second term. Again applying the distributive law when necessary, and making sure that it is recognized that increasing the second element by a is the same as multiplying by w^a. As mentioned above, exponentiating is the same as multiplying the exponent and then removing the added part. This was my favourite method of storing ordinals because it's rather unique and interesting, and has a high limit which is easy to achieve.
The other two notations are likely possible, and I've had ideas for how to do so. Veblen Hierarchy could be stored similarly to TAN though storing an array of terms like CNF and ECNF, and each term is an array in Veblen Style, though each element must also be an array of terms to allow the ability to store all ordinals. Ordinal collapsing functions would be more difficult, I propose storing the symbolic string as an abstract syntax tree, the primary issue would be normalization as that could get out of control very easily,
*the study and nomenclature of large finite numbers, though as fast growing and other ordinal hierarchies play an important role in such, there is a large variety of ordinal notation developed, though most would be incredibly difficult to program.

Related

Can one encrypt an n-digit number, returning a unique n-digit number?

StackOverflow warns me that I may be down-voted for this question, but I'd appreciate your not doing so, as I post this simply to try to understand a programming exercise I've been posed with, and over which I've been puzzling a while now.
I'm doing some javascript coding exercises and one of the assignments was to devise an "encryption function", encipher, which would encrypt a 4-digit number by multiplying it by a number sufficiently low such that none of its digits exceeds 9, so that a 4-digit number is returned. Thus
encipher(0204)
might yield
0408
where the multiplier would have been 2. -- This is very basic material, simply to practice the Javascript. -- But as far as I can see, the numbers returned can never be deciphered (which is the next part of the exercise). Even if you store a dictionary internal to encipher, along the lines of
{'0408':'2'}, etc
so that you could do a lookup on 0408 and return 0204, these entries could not be assured to be unique. If one for example were to get the number 9999 to be deciphered, one would never know whether the original number was 9999 (multiplied by 1), 3333 (multiplied by 3) or 1111 (multiplied by 9). Is that correct? I realise this is a fairly silly and artificial problem, but I'm trying to understand if the instructions to the exercise are not quite right, or if I'm missing something. Here is the original problem:
Now, let's add one more level of security. After changing the position of the digits, we will multiply each member by a number whose multiplication does not exceed 10. (If it is higher than 10, we will get a two-digit multiplication and the code will no longer be 4 values). Now, implement in another function the decrypter (), which will receive as an argument an encrypted code (and correspondingly multiplied in the section above and return the decrypted code.
Leaving the exercise behind, I'm just curious whether there exists any way to "encrypt" (when I say "encrypt", I mean at a moderate javascript level, as I'm not a cryptography expert) an n-digit number and return a unique n-digit number?
Thanks for any insights. --
encrypt a 4-digit number by multiplying it by a number sufficiently low such that none of its digits exceeds 9, so that a 4-digit number is returned
If your input is 9999, there is no integer other than 1 or 0 that you can multiply your input by and get a positive number with a maximum of 4 digits. Therefore, there is no solution that involves only integer multiplication. However, integer multiplication can be used as part of an algorithm such as rotating digits (see below).
If instead you're looking for some sort of bijective algorithm (one that uniquely maps A to B and B to A), you can look at something like rotating the digits left or right, reversing the order of the digits, or using a unique mapping of each individual digit to another. Those can also be mixed.
Examples
Rotate
1234 -> 2341
Reverse
1234 -> 4321
Remap digits e.g. 2 mapped to 8, 3 mapped to 1
2323 -> 8181
Note that none of these are cryptographically sound methods to encrypt information, but they do seem to more-or-less meet the objectives of the exercise.

Pitfalls with using scientific notation in JavaScript

This question is not seeking developer code formatting opinions. Personally, I prefer to use scientific notation in my JS code when I can because I believe it is more readable. For me, 6e8 is more readable than 600000000. That being said, I am solely looking for potential risks and disadvantages specifying numbers in scientific notation in JS. I don't see it often in the wild and was wondering if there is technical reasoning for that or if it simply because of developer's druthers.
You don't see scientific notation "often in the wild" because the only numbers that actually get typed in JS tend to be constants:
Code-centric constants (such as enums and levels) tend to be small.
Physical/mathematical constants (such as π or e) tend to be highly specific.
Neither of these benefit from scientific notation too much.
I have seen Plank's constant 'in the wild' as:
const h = 6.62607004e-34;
console.log('Plank', h);
The other place it often makes sense is time limits, for instance the number of ms in a day as 864e5. For instance:
function addDaysToDate(date, days) {
if (days === 0)
return date;
date.setTime(864e5 * days + date.valueOf());
return date;
}
const now = new Date();
const thisTimeTomorrow = addDaysToDate(now, 1);
console.log('This time tomorrow', thisTimeTomorrow);
I don't think there's any technical reason not to use this notation, it's more that developers avoid hard coding numbers at all.
I don't think there are any risks. You may have to be careful with numbers in strings, but if you're doing that then this syntax is a far smaller issue than, say, number localisation (for instance a DE user entering "20.000,00", expecting 2e4, but getting 2e6 thanks to invariant number formatting swapping the thousand and decimal separators).
I'd add that JS will output that syntax by default anyway for small numbers, but avoids for large numbers up to a point (which varies by browser):
console.log('Very small', 1234 / 100000000000)
console.log('Large, but still full in some browsers', 1e17 * 1234)
console.log('Large, scientific', 1e35 * 1234)
From O. R. Mapper in this question:
Human users are not the only ones who want to read numbers. It seems
D3 will throw an exception when encountering a translate
transformation that contains coordinates in scientific notation
In addition, if you want change the string representation, as opposed to just what the literal looks like in your source, you'll have to be careful with serialized/stored data.
Also, from experience, often times you can have large numbers whose significance is in their individual digits like an ID or phone number. In this case, reducing these numbers to scientific notation hurts readability.
E-notation indicates a number that should be multiplied by 10 raised
to a given power.
is not scientific exponential notation . One pitfall is that e "times ten raised to the power of" in JavaScript is not The number e the base of the natural logarithm, represented at browser as Math.E. For individuals familiar with the mathematical constant e, JavaScript e has an entirely different meaning. 6 * Math.pow(10, 8) returns expected result and does not include use of the JavaScript artifact e.
Although the E stands for exponent, the notation is usually referred
to as (scientific) E-notation rather than (scientific) exponential
notation. The use of E-notation facilitates data entry and readability
in textual communication since it minimizes keystrokes, avoids reduced
font sizes and provides a simpler and more concise display, but it is
not encouraged in publications. Submission Guidelines for Authors:
HPS 2010 Midyear
Proceedings

Unable to increase extremely large number by one in JavaScript

I'm trying to increase by one this number: 9223372036854775808:
var number = 9223372036854775808;
var plusOne = number + 1;
This should yield 9223372036854775809, but it instead yields 9223372036854776000.
Why? More important, how can I fix this?
The largest representable number in JavaScript is (2^53) - 1, or, written out, 9007199254740991. The number you have, 9223372036854775808, is more than 1024 times that quantity.
If you want to work with numbers larger than the one above, you should use a big integer library. JavaScript does not have one built in, however, so you'll need to grab it yourself. Personally, I use big-integer when I'm working on things that deal with really large numbers, e.g., Project Euler.
This is to do with JavaScript storing numbers internally as (double precision) floating point. As you go up the scale of floating point numbers, the numbers get more and more sparse until the point where you get incorrect results, because the next representable number is more that 1 away (As in your example). To properly handle large numbers, you will need to use a proper large number library such as javascript-bignum. If you only need integers, you can use BigInteger.js

JavaScript Math.floor: how guarantee number will round down?

I want to normalize an array so that each value is
in [0-1) .. i.e. "the max will never be 1 but the min can be 0."
This is not unlike the random function returning numbers in the same range.
While looking at this, I found that .99999999999999999===1 is true!
Ditto (1-Number.MIN_VALUE) === 1 But Math.ceil(Number.MIN_VALUE) is 1, as it should be.
Some others: Math.floor(.999999999999) is 0
while Math.floor(.99999999999999999) is 1
OK so there are rounding problems in JS.
Is there any way I can normalize a set of numbers to lie in the range [0,1)?
It may help to examine the steps that JavaScript performs of each of your expressions.
In .99999999999999999===1:
The source text .99999999999999999 is converted to a Number. The closest Number is 1, so that is the result. (The next closest Number is 0.99999999999999988897769753748434595763683319091796875, which is 1–2–53.)
Then 1 is compared to 1. The result is true.
In (1-Number.MIN_VALUE) === 1:
Number.MIN_VALUE is 2–1074, about 5e–304.
1–2–1074 is extremely close to one. The exact value cannot be represented as a Number, so the nearest value is used. Again, the nearest value is 1.
Then 1 is compared to 1. The result is true.
In Math.ceil(Number.MIN_VALUE):
Number.MIN_VALUE is 2–1074, about 5e–304.
The ceiling function of that value is 1.
In Math.floor(.999999999999):
The source text .999999999999 is converted to a Number. The closest Number is 0.99999999999900002212172012150404043495655059814453125, so that is the result.
The floor function of that value is 0.
In Math.floor(.99999999999999999):
The source text .99999999999999999 is converted to a Number. The closest Number is 1, so that is the result.
The floor function of 1 is 1.
There are only two surprising things here, at most. One is that the numerals in the source text are converted to internal Number values. But this should not be surprising. Of course text has to be converted to internal representations of numbers, and the Number type cannot perfectly store all the infinitely many numbers. So it has to round. And of course numbers very near 1 round to 1.
The other possibly surprising thing is that 1-Number.MIN_VALUE is 1. But this is actually the same issue: The exact result is not representable, but it is very near 1, so 1 is used.
The Math.floor function works correctly. It never introduces any error, and you do not have to do anything to guarantee that it will round down. It always does.
However, since you want to normalize numbers, it seems likely you are going to divide numbers at some point. When you divide, there may be rounding problems, because many results of division are not exactly representable, so they must be rounded.
However, that is a separate problem, and you have not given enough information in this question to address the specific calculations you plan to do. You should open a separate question for it.
Javascript will treat any number between 0.999999999999999994 and 1 as 1, so just subtract .000000000000000006.
Of course that's not as easy as it sounds, since .000000000000000006 is evaluated as 0 in Javascript, so you could do something like:
function trueFloor(x)
{
x = x * 100;
if(x > .0000000000000006)
x = x - .0000000000000006;
x = Math.floor(x/100);
return x;
}
EDIT: Or at least you'd think you could. Apparently JS casts .99999999999999999 to 1 before passing it to a function, so you'd have to try something like:
trueFloor("0.99999999999999999")
function trueFloor(str)
{
x=str.substring(0,9) + 0;
return Math.floor(x); //=> 0
}
Not sure why you'd need that level of precision, but in theory, I guess it works. You can see a working fiddle here
As long as you cast your insanely precise float as a string, that's probably your best bet.
Please understand one thing: this...
.999999999999999999
... is just a Number literal. Just as
.999999999999999998
.999999999999999997
.999999999999999996
...
... you see the pattern.
How JavaScript treats these literals is completely another story. And yes, this treatment is limited by the number of bits that can be used to store a Number value.
The number of possible floating point literals is infinite by definition - no matter how small is the range set for them. For example, take the ones shown above: how many of numbers very close to 1 you may express? Right, it's infinite: just keep appending 9 to the line.
But the container for each Number value is quite finite: it has 64 bits. That means, it can store 2^64 different values (Infinite, -Infinite and NaN among them) - and that's all.
You want to work with such literals anyway? Use Strings to store them, not Numbers - and some BigMath JS library (take your pick) to work with those values - as Strings, again.
But from your question it looks like you're not, as you talked about array of Numbers - Number values, that is. And in no way there can be .999999999999999999 stored there, as there is no such Number value in JavaScript.

True or better Random numbers with Javascript [duplicate]

This question already has answers here:
Secure random numbers in javascript?
(10 answers)
Closed 12 months ago.
I have all kinds of resources that rely on javascript random numbers. However, I've been seeing a lot of problems where random isn't so random because of the way I'm generating random numbers.
Is there any javascript resource for me to generate true, or just better random numbers?
I know that I can interface with Random.org, but what other options do I have?
I'm using:
function rand( lowest, highest){
var adjustedHigh = (highest - lowest) + 1;
return Math.floor(Math.random()*adjustedHigh) + parseFloat(lowest);
}
Assuming you're not just seeing patterns where there aren't any, try a Mersenee Twister (Wikipedia article here). There are various implementations like this one on github.
Similar SO question:
Seedable JavaScript random number generator
If you want something closer to truly random, then consider using the random.org API to get truly random numbers, although I would suggest only using that to seed, not for every number, as you need to abide by their usage limits.
Tweaking numbers so they "look random"
I agree with Phil H that humans are so good at finding patterns that they often think they see patterns even in "perfectly random" sequences of numbers (clustering illusion, apophenia, gambler's fallacy, etc).
Plots of true random positions generally have lots of clumps and points that "coincidentally" fall very close together, which looks pretty suspicious.
Artists often take completely randomly generated patterns and "nudge" them to make them appear "more random", even though that careful nudging actually makes the pattern less random (a), (b), (c), (d), etc.
Alternatively, a low-discrepancy sequence sometimes "looks better" than a true random sequence and is much faster to generate.
Fast random number generators
There are many "random number generators" across a whole spectrum from "extremely fast" to "relatively slow" and from "easy for even a human to see patterns" to "unlikely that unassisted humans could ever see any patterns" to "cryptographically secure and, after seeded with adequate amounts of entropy, as far as we can tell, indistinguishable from random to any attacker using less than all the energy produced by humanity for a month."
Non-cryptographic-strength random number generators that still give excellent output (unlikely that unassisted humans could ever see any patterns) include the Mersenne twister, multiply-with-carry, Lagged Fibonacci generator, Well equidistributed long-period linear, Xorshift, etc.
Cryptographic random number techniques that work with some browsers
I hear that Cryptocat and other JavaScript applications use the convenient window.crypto.getRandomValues() or window.msCrypto.getRandomValues() or SubtleCrypto.generateKey() functions that are designed to generate cryptographic random numbers. Unfortunately, that function is not available in IE 11 and below.
Since web browsers use random numbers all the time (for every "https://" page they fetch), it's quite likely that these functions (where available) may run faster than most random number generators written in JavaScript -- even non-cryptographic algorithms.
Cryptographic random number techniques compatible with ancient and modern browsers
One way to generate true random numbers in JavaScript is to capture mouse events and add them into a pool of entropy, keeping track of some (hopefully conservative) estimate of the entropy added. Once the pool is "full" (estimates indicate that at least 128 bits of entropy have been added), use some cryptographically secure random number generator to generate random numbers from the pool -- typically by using a one-way hash so that a sequence of a few thousand output numbers are not enough to deduce the state of the entropy pool and hence predict the next output number.
One implementation: http://lightsecond.com/passphrase.html
Further reading
window.crypto
Compatibility of window.crypto.getRandomValues()
Secure random numbers in javascript?
https://security.stackexchange.com/questions/20029/generate-cryptographically-strong-pseudorandom-numbers-in-javascript
Is there any built in browser support for crypto random numbers in IE and Webkit? Firefox has window.crypto
Better random function in JavaScript
While looking for an alternative for Math.random I stumbled on this question.
While those are valid answers, the solution that worked for me was simply using Math.random twice.
And use a modulus on the decimals of the float.
Basically to increase the randomness.
Maybe it might be usefull for some who were guided by google to this question.
Here's a snippet with the function, and one that runs it a million times.
function rand(min, max){
return (Math.floor(Math.pow(10,14)*Math.random()*Math.random())%(max-min+1))+min;
}
// testing rand
function rollRands(min, max, rolls) {
let roll = 0, n = 0;
let counts = {};
for(let i = min; i <= max; i++){
counts[i]=0
}
while (roll < rolls){
roll++;
counts[rand(min,max)]++;
}
return counts;
}
console.log(rollRands(36, 42, 1000000));
Rando.js is cryptographically secure. It's basically window.crypto.getRandomValues() that uses window.msCrypto.getRandomValues() as a failsafe and Math.random() as a last resort failsafe, but it's easier to implement and use. Here's a basic cryptographically secure random [0, 1) number:
console.log(rando());
<script src="https://randojs.com/2.0.0.js"></script>
Nice and easy. If that's all you wanted, you're good to go. If you want it to do more for you, it's also capable of all this:
console.log(rando(5)); //an integer between 0 and 5 (could be 0 or 5));
console.log(rando(5, 10)); //a random integer between 5 and 10 (could be 5 or 10));
console.log(rando(5, "float")); //a floating-point number between 0 and 5 (could be exactly 0, but never exactly 5));
console.log(rando(5, 10, "float")); //a floating-point number between 5 and 10 (could be exactly 5, but never exactly 10));
console.log(rando(true, false)); //either true or false
console.log(rando(["a", "b"])); //{index:..., value:...} object representing a value of the provided array OR false if array is empty
console.log(rando({a: 1, b: 2})); //{key:..., value:...} object representing a property of the provided object OR false if object has no properties
console.log(rando("Gee willikers!")); //a character from the provided string OR false if the string is empty. Reoccurring characters will naturally form a more likely return value
console.log(rando(null)); //ANY invalid arguments return false
//Prevent repetitions by grabbing a sequence and looping through it
console.log(randoSequence(5)); //an array of integers from 0 through 5 in random order
console.log(randoSequence(5, 10)); //an array of integers from 5 through 10 in random order
console.log(randoSequence(["a", "b"])); //an array of {index:..., value:...} objects representing the values of the provided array in random order
console.log(randoSequence({a: 1, b: 2})); //an array of {key:..., value:...} objects representing the properties of the provided object in random order
console.log(randoSequence("Good gravy!")); //an array of the characters of the provided string in random order
console.log(randoSequence(null)); //ANY invalid arguments return false
<script src="https://randojs.com/2.0.0.js"></script>
It supports working with jQuery elements too, but I left that out of this demo so I wouldn't have to source in jQuery. If you need that, just check it out on the GitHub or website.
There seems to be slight confusion here between two things that are very different:
random numbers;
pseudorandom numbers.
Apologies to those who know this already, but the two are worlds apart. Pseudorandom numbers appear random and may even pass sophisticated tests of randomness, but they are deterministic. Because of this, they are useless for cryptography, and may have other flaws where true randomness is required.
True randomness is non-deterministic, and thus unpredictable. A key concept here is one of entropy, or the amount of non-redundant information contained. There is a limited number of ways of obtaining truly random data. 'Good' sources are:
Radioactive decay — often difficult to do;
Background radio noise — contrary to popular believe, this is mostly not related to the background microwave radiation from the big bang, but more parochial;
The noise from electrons moving across a reverse-biased Zener diode: actually quite useful and easy to implement in practice, with simple circuitry.
Other 'sources of randomness' like mouse movements and internal variations in computer disk timing, etc. are often harnessed, but may be less-than-perfect. Generally, I've found that it's easier to access the entropy pool on a Linux system than under Windows, but this may just be personal bias.
If you just want random-appearing numbers, then yes, using the Mersenne twister is a viable option. It jumps around like crazy. If you're generating random numbers to use as e.g. version 4 UUIDs, then you need to be more careful. You can't simply 'add entropy' if it's not there, even by applying deterministic cryptographic functions.
If you intend to use your randomness for cryptography, you should also be intensely aware of the many ways your source of randomness can become compromised. For example, if you're using an Internet-based 'source of randomness', who can tap into this?
Even better, you can use quantum cryptography to generate randomness that is very hard to predict. You can use the ANU Quantum Random Numbers API for some randomness that is coercible into a number similarly output by Math.random.
you can generate a pool of random numbers just by requesting some data asynchronously because performance.now() gives you time precision up to microseconds. Then use the response time as a salt in a randomising algorithm,
var randomNumbers = [];
for(var i = 0; i < 10; i++) {
setTimeout(function () {
var timeStart = performance.now();
xhttp = new XMLHttpRequest();
xhttp.open('GET', 'https://cdn.polyfill.io/v2/polyfill.min.js?rand=' + Math.random(), true);
xhttp.onload = function () {
var timeEnd = performance.now() - timeStart;
var rNumber = parseInt(timeEnd.toString().replace('.', ''));
randomNumbers.push(rNumber)
};
xhttp.send();
}, i * 10);
}
There are many factors that will affect this time:
browser speed
route one way
server response time
route back
It's not good to generate millions of numbers this way but a few. Maybe concatenate a few results to get a good, long random number.

Categories

Resources