Тобто, V8 JavaScript - це похідний механізм Smalltalk. (1980-ті - дотепер) Двигуни Lisp та Smalltalk підтримують багатоточну арифметику з використанням <LargeInteger>, яке іноді називають <BigInt>. Спойлер, команда Dart в Google - це, в основному, купа колишніх Smalltalker, які об'єднують свій досвід у просторі JS.
Ці типи чисел мають необмежену точність і, як правило, використовуються як будівельні блоки для надання об'єктів <Rational: Fraction>, чисельник і знаменник яких може бути будь-яким типом числа, включаючи <BigInt>. Завдяки цьому можна зобразити дійсні числа, уявні числа, і робити це з досконалою точністю на ірраціональних числах, таких як (1/3).
Примітка: Я давно впроваджую та розроблюю Smalltalk, JS та інші мови та їх механізми та фреймворки.
Якщо це зробити належним чином <BigInt> для мультиточної арифметики як стандартної функції JavaScript, це відкриє двері до величезного набору операцій, включаючи нативну ефективну криптографію (що легко зробити за допомогою багатоточних чисел).
Наприклад, в одному з моїх двигунів smalltalk 1998 року на процесорі 2,3 ГГц я щойно працював:
[10000 factorial] millisecondsToRun => 59ms
10000 factorial asString size => 35660 digits
[20000 factorial] millisecondsToRun => 271ms
20000 factorial asString size => 77338 digits
Визначається як: (ілюструє <BigInt>
багатоточність у дії)
factorial
"Return the factorial of <self>."
| factorial n |
(n := self truncate) < 0 ifTrue: [^'negative factorial' throw].
factorial := 1.
2 to: n do:
[:i |
factorial := factorial * i.
].
^factorial
Робота двигуна V8 від Ларса Бака (сучасника моєї роботи) походить від Animorphic Smalltalk з роботи САМД Девіда Унгара, похідної від Smalltalk-80, а згодом переросла в JVM і перероблена Lars for Mobile, що з'явилася пізніше як основа двигуна V8.
Я згадую це тому, що і Animorphic Smalltalk, і QKS Smalltalk підтримують анотації типів, які дозволяють двигуну та інструментам міркувати про код подібним чином, який TypeScript робив спробу для JavaScript.
Цей натяк на анотації та його використання мовою, інструментами та механізмами виконання дає можливість підтримувати мультиметоди (а не подвійне відправлення), необхідні для належної підтримки мультиточних арифметичних правил просування та примусу.
Що, в свою чергу, є ключовим для підтримки 8/16/32/64 int / uints та багатьох інших числових типів у когерентній структурі.
<Magnitude|Number|UInt64>
Приклади багато методів з QKS Smalltalk 1998
Integer + <Integer> anObject
"Handle any integer combined with any integer which should normalize
away any combination of <Boolean|nil>."
^self asInteger + anObject asInteger
-- multi-method examples --
Integer + <Number> anObject
"In our generic form, we normalize the receiver in case we are a
<Boolean> or <nil>."
^self asInteger + anObject
-- FFI JIT and Marshaling to/from <UInt64>
UInt64 ffiMarshallFromFFV
|flags| := __ffiFlags().
|stackRetrieveLoc| := __ffiVoidRef().
""stdout.printf('`n%s [%x]@[%x] <%s>',thisMethod,flags,stackRetrieveLoc, __ffiIndirections()).
if (flags & kFFI_isOutArg) [
"" We should handle [Out],*,DIM[] cases here
"" -----------------------------------------
"" Is this a callout-ret-val or a callback-arg-val
"" Is this a UInt64-by-ref or a UInt64-by-val
"" Is this an [Out] or [InOut] callback-arg-val that needs
"" to be updated when the callback returns, if so allocate callback
"" block to invoke for doing this on return, register it as a cleanup hook.
].
^(stackRetrieveLoc.uint32At(4) << 32) | stackRetrieveLoc.uint32At(0).
-- <Fraction> --
Fraction compareWith: <Real> aRealValue
"Compare the receiver with the argument and return a result of 0
if the received <self> is equal, -1 if less than, or 1 if
greater than the argument <anObject>."
^(numerator * aRealValue denominator) compareWith:
(denominator * aRealValue numerator)
Fraction compareWith: <Float> aRealValue
"Compare the receiver with the argument and return a result of 0
if the received <self> is equal, -1 if less than, or 1 if
greater than the argument <anObject>."
^self asFloat compareWith: aRealValue
-- <Float> --
Float GetIntegralExpAndMantissaForBase(<[out]> mantissa, <const> radix, <const> mantissa_precision)
|exp2| := GetRadix2ExpAndMantissa(&mantissa).
if(radix = 2) ^exp2.
|exp_scale| := 2.0.log(radix).
|exp_radix| := exp2 * exp_scale.
|exponent| := exp_radix".truncate".asInteger.
if ((|exp_delta| := exp_radix - exponent) != 0) [
|radix_exp_scale_factor| := (radix.asFloat ^^ exp_delta).asFraction.
"" Limit it to the approximate precision of a floating point number
if ((|scale_limit| := 53 - mantissa.highBit - radix.highBit) > 0) [
"" Compute the scaling factor required to preserve a reasonable
"" number of precision digits affected by the exponent scaling
"" roundoff losses. I.e., force mantissa to roughly 52 bits
"" minus one radix decimal place.
|mantissa_scale| := (scale_limit * exp_scale).ceiling.asInteger.
mantissa_scale timesRepeat: [mantissa :*= radix].
exponent :-= mantissa_scale.
] else [
"" If at the precision limit of a float, then check the
"" last decimal place and follow a rounding up rule
if(exp2 <= -52 and: [(mantissa % radix) >= (radix
mantissa := (mantissa
exponent :+= 1.
].
].
"" Scale the mantissa by the exp-delta factor using fractions
mantissa := (mantissa * radix_exp_scale_factor).asInteger.
].
"" Normalize to remove trailing zeroes as appropriate
while(mantissa != 0 and: [(mantissa % radix) = 0]) [
exponent :+= 1.
mantissa :
].
^exponent.
Я би очікував, що деякі подібні шаблони почнуть з'являтися для підтримки JavaScript UIn64 / Int64 та інших структурних або числових типів, коли <BigInt> розвивається.