Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Number encoding #9

Open
837951602 opened this issue Feb 13, 2017 · 17 comments
Open

Number encoding #9

837951602 opened this issue Feb 13, 2017 · 17 comments

Comments

@837951602
Copy link
Contributor

837951602 commented Feb 13, 2017

There should only be XXXeYYY and (AAA)(.BBB) -- since point costs 72 chars far larger than '9' 47, it's never cheap to use both.
With x being a positive finite number, turning x to XXXeYYY style uses x.toExponential().replace(/^(\d)\.?(\d*)e(.*)$/,function(x,a,b,c){return a+b+'e'+(c-b.length)}) and to (AAA)(.BBB) use Number.prototype.forceFixed=function(){var t=this.toString().split('e');if(t.length==1)return t.replace(/^0/,'');t[0]=t[0].replace(/\./,'');return t[1]>0?t[0]+Array(2- -t[1]-t[0].length).join(0):'.'+Array(-t[1]).join('0')+t[0]}? (code not tested fully)

@837951602
Copy link
Contributor Author

837951602 commented Feb 14, 2017

It may be an idea to write -999999 as -1000000+1, and 1e12+1 to 1e12+1 but I don't know whether it's easy or difficult to achieve

@837951602
Copy link
Contributor Author

1.0000000000001e+113
+(+(+!![]+(!![]+[])[!![]+!![]+!![]]+(+!![])+(!![]+!![]+!![]))+(+!![])+(!![]+[])[!![]+!![]+!![]]+(+!![])+(+[])+(+[]))

@fasttime
Copy link
Owner

-999999 can be written as -1000000 + 1 and 1e12+1 as 1e12+1, that's fine because those are integers between Number.MAX_SAFE_INTEGER and -Number.MAX_SAFE_INTEGER. It wouldn't be too difficult either.

I'm not sure about 1.0000000000001e+113: this is a floating-point number that is only approximately equal to the sum of two powers of 10. Nothing in ECMAScript or IEEE-754 says that it couldn't be rounded to something slightly larger or slightly smaller, but most of all I don't know how consistent different engines are when calculating the sum of non-safe integers. JScrewIt must work with many different engines and I wouldn't be surprised if something that gives 1.000...0001 in my browser gave 1 in another one's browser.
Long story short: this needs more experimentation and extensive testing if we don't want to break something accidentally.

@837951602
Copy link
Contributor Author

JavaScript Numbers are Always 64-bit Floating Point
Unlike many other programming languages, JavaScript does not define different types of numbers, like integers, short, long, floating-point etc.

JavaScript numbers are always stored as double precision floating point numbers, following the international IEEE 754 standard.

This format stores numbers in 64 bits, where the number (the fraction) is stored in bits 0 to 51, the exponent in bits 52 to 62, and the sign in bit 63:

Value (aka Fraction/Mantissa) Exponent Sign
52 bits (0 - 51) 11 bits (52 - 62) 1 bit (63)
Precision
Integers (numbers without a period or exponent notation) are considered accurate up to 15 digits.

Example
var x = 999999999999999; // x will be 999999999999999
var y = 9999999999999999; // y will be 10000000000000000
Try it Yourself »
The maximum number of decimals is 17, but floating point arithmetic is not always 100% accurate:

Source: http://w3schools.bootcss.com/js/js_numbers.html

@837951602
Copy link
Contributor Author

I'm not sure about 1.0000000000001e+113: this is a floating-point number that is only approximately equal to the sum of two powers of 10.

The expression is not 1e113+1e100 but +((1e13+1)+'e100')

@fasttime
Copy link
Owner

fasttime commented Feb 15, 2017

@837951602 Ah, I see. But why not +(1e12+'1e100')? That could be implemented as a string cluster optimization, specifically for the case of a string containing a nonzero digit followed by many zeros.

@837951602
Copy link
Contributor Author

837951602 commented Feb 15, 2017

Yes +(1e12+'1e100') is a better choice yet +((1e10+1)+'e100') is shorter than +(1e9+'1e100')

@837951602
Copy link
Contributor Author

1e-292 +(+!![]+(!![]+[])[!![]+!![]+!![]]+(+((+(+!![]+[+!![]]+(!![]+[])[!![]+!![]+!![]]+(!![]+!![])+(+[]))+[])[+!![]]+(+[])+(+[])+(+[])+(+[])+(+[])+(+[])+(+[])+(+[])+(+[])+(+!![]))+[])[!![]+!![]]+(!![]+!![])+(!![]+!![]+!![]+!![]+!![]+!![]+!![]+!![]+!![])+(!![]+!![])) 259c
+(1+'e'+(10-302)) +(+!![]+(!![]+[])[!![]+!![]+!![]]+(+(+!![]+[+[]])+(+((+((+(+!![]+[+!![]]+(!![]+[])[!![]+!![]+!![]]+(!![]+!![])+(+[]))+[])[+!![]]+(+[])+(+[])+(+[])+(+[])+(+[])+(+[])+(+[])+(+[])+(+[])+(+!![]))+[])[!![]+!![]]+(!![]+!![]+!![])+(+[])+(!![]+!![]))))) 245c
same type of -999999 as -1000000+1

@837951602
Copy link
Contributor Author

837951602 commented Mar 16, 2017

Not sure about if float values or exceeded_safe_integer calculated get the same value? If so, 0.9999999999999998(822c) can't be +('.'+(1e16-2))(323c) or 1-2e-16(339c) but only +('.'+(1e15-1)+8)(358c)

@837951602
Copy link
Contributor Author

So why is '-' translated into "1e-10"[2] instead of "1e-7"[2]? If because of compatible why no this feature

@837951602
Copy link
Contributor Author

1e-100 208c
+(1e-10+[0]) 146c

@fasttime
Copy link
Owner

I don't know why "-" is defined how it is! This should be analyzed ASAP.

@837951602
Copy link
Contributor Author

837951602 commented Mar 17, 2017

(ECMA-262 5th edition December 2009, P48)
http://www.ecma-international.org/publications/files/ECMA-ST-ARCH/ECMA-262%205th%20edition%20December%202009.pdf
9.8.1 ToString Applied to the Number Type
The abstract operation ToString converts a Number m to String format as follows:

  1. If m is NaN, return the String "NaN".
  2. If m is +0 or −0, return the String "0".
  3. If m is less than zero, return the String concatenation of the String "-" and ToString(−m).
  4. If m is infinity, return the String "Infinity".
  5. Otherwise, let n, k, and s be integers such that k ≥ 1, 10k−1 ≤ s < 10k
    , the Number value for s × 10n−k
    is m, and
    k is as small as possible. Note that k is the number of digits in the decimal representation of s, that s is not
    divisible by 10, and that the least significant digit of s is not necessarily uniquely determined by these
    criteria.
  6. If k ≤ n ≤ 21, return the String consisting of the k digits of the decimal representation of s (in order, with no
    leading zeroes), followed by n−k occurrences of the character ‘0’.
  7. If 0 < n ≤ 21, return the String consisting of the most significant n digits of the decimal representation of s,
    followed by a decimal point ‘.’, followed by the remaining k−n digits of the decimal representation of s.
  8. If −6 < n ≤ 0, return the String consisting of the character ‘0’, followed by a decimal point ‘.’, followed by
    −n occurrences of the character ‘0’, followed by the k digits of the decimal representation of s.
  9. Otherwise, if k = 1, return the String consisting of the single digit of s, followed by lowercase character ‘e’,
    followed by a plus sign ‘+’ or minus sign ‘−’ according to whether n−1 is positive or negative, followed by
    the decimal representation of the integer abs(n−1) (with no leading zeros).
  10. Return the String consisting of the most significant digit of the decimal representation of s, followed by a
    decimal point ‘.’, followed by the remaining k−1 digits of the decimal representation of s, followed by the
    lowercase character ‘e’, followed by a plus sign ‘+’ or minus sign ‘−’ according to whether n−1 is posi

@837951602
Copy link
Contributor Author

aemkei's jsfuck main page also said "0.0000001"->'1e-7' and get '-'. but creating it's 1e-10
aemkei/jsfuck@4a5ff0e

@fasttime
Copy link
Owner

Made a branch to test the "-" optimization: https://github.com/fasttime/JScrewIt/tree/minus-sign. Looks good so far. @837951602 Kudos for spotting this!

@837951602
Copy link
Contributor Author

9.999999999999997e+214 870c
+'999999999999999.7e200' 865c

@fasttime
Copy link
Owner

fasttime commented Jan 1, 2019

9.999999999999997e+214 870c
+'999999999999999.7e200' 865c

This is now done with 139479b in the update branch. Preview here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants