Proposal: 1) Number (integer or decimal) to Array 2) Array to Number (integer or decimal)

Naveen Chawla naveen.chwl at gmail.com
Mon Mar 11 19:15:12 UTC 2019


If only some of my proposals that were actually useful got this much
attention

On Mon, 11 Mar 2019, 4:33 pm Jeremy Martin, <jmar777 at gmail.com> wrote:

> With respect, it's still not clear how you want to interact with the array
> of values once you've destructured a Float into your array format.
>
> If all you have is an array of single-digit numbers that represent the
> values in the tenths/hundredths/etc. positions of the source number, how
> does this actually circumvent the challenges of representing Decimal values
> that aren't exactly representable as a Float?
>
> To illustrate this challenge, let's use the classic example we've all seen
> hundreds of times:
>
> > .1 + .2
> 0.30000000000000004
>
> For a long time, all the reading I would do about *why* this produced a
> weird result would *sort* of make sense and *sort* of confuse me. That
> is, I could understand *why* 3/10ths isn't representable as a Float, but
> then I would get confused by the fact that I could type `.3` into a REPL,
> and it would *actually work *(??!):
>
> > .3
> 0.3
>
> I mean, who's lying? How come `.3` works fine when I just type it
> straight in, and `.1 + .3` works just fine, but there's just these
> specific cases like `.1 + .2` where all of a sudden `.3` decides not to
> be representable again?
>
> I admit this is conjecture, but maybe that's part of the confusion
> motivating this proposal? And maybe the idea is that if we can break `.1`
> and `.2` into some sort of an array structure (e.g., [0, 1] and [0, 2]), then
> we can add the individual parts as integers (giving us something like [0,
> 3]) which we can then just convert back into a single numeric value at
> the end as 0.3, and voila, no 0.30000000000000004 shenanigans?
>
> The problem is that this all builds on a fundamental misunderstanding of
> what's going. Let's revisit the basic example of entering a value into the
> REPL:
>
> > .3
> 0.3
>
> This, as I stated earlier, contributed greatly to my own hangups in
> understanding what was going on here. What I personally didn't understand
> was that the `0.3` value you see above isn't actually the *Decimal* value
> 0.3. It's just a *very* close approximation of 0.3. (so close, in fact,
> that 0.3 is the *closest* Decimal value that it can be rounded to, so
> that's what gets emitted).
>
> So, going back to our earlier example, why do we get a *different* output
> when we're dealing with the result of a mathematical operation, as opposed
> to getting the *same* very close approximation of 0.3 that we get when we
> simply type it into the REPL?
>
> > .1 + .2
> 0.30000000000000004
>
> The answer lies in the fact that 0.1 and 0.2 *also* can't be represented
> exactly as Floats. Just like we saw with 0.3, we can type them into the
> REPL and see a value that looks the exact same being emitted back at us:
>
> > .1
> 0.1
> > .2
> 0.2
>
> ...but also like we saw with 0.3, they only *look* like accurate
> representations. Once again, 0.1 and 0.2 are just the closest Decimal
> values that the underlying Float values can be rounded to for display.
>
> This rounding behavior, then, is what causes us to get 0.30000000000000004
> when we add them together, because the *slight* rounding error with 0.1
> and the *slight* rounding error with 0.2 compound to result in a Float
> that no longer rounds closer to 0.3, and instead closer to the "wrong"
> Decimal value that we see emitted before.
>
> It's worth noting that this same behavior applies to, e.g., 0.1 + 0.3, even
> though that *looks* like it produces the correct result of 0.4. In
> reality, however, this is just a case where the rounding errors have the
> effect of (almost) canceling each other out, such that the resulting Float
> rounds closer to 0.4 than any other value for display purposes (despite
> being only negligibly more accurate than our 0.30000000000000004 result
> was).
>
> Ok, so why am I trying to explain all this? Because I'm trying to
> illustrate why it sounds like this proposal doesn't actually solve the
> problem that you want it to. Is it possible to standardize a system for
> transformations and math operations like the following?
>
>   const arg1 = numberToArray(0.1) // [0, 1]
>   const arg2 = numberToArray(0.2) // [0, 2]
>
>   const arraySum = addArrayNumbers(arg1, arg2) // [0, 3]
>
>   const result = arrayToNumber(arraySum) // 0.3
>
> Sure, and at the very end, you actually get a value that *looks* right (
> 0.3, yay!). But *it's still not actually 0.3.* So what become the
> motivation for this? You have a solution that, in terms of memory and CPU
> cycles, is orders of magnitude more costly to calculate than `0.1 + 0.2` as
> a plain JavaScript expression, and in return you get a result that is, *at
> best*, infinitesimally more accurate than the alternative when carried
> all the way out to the quadrillionths place or greater.
>
> Do you actually have a use case for mathematical operations that are fault
> tolerant enough to represent Decimal values as Floats, but that fault
> tolerance is sensitive to very, very specific rounding behavior at the
> quadrillionths level? I can't even imagine what that use case would be.
>
> On Mon, Mar 11, 2019 at 10:06 AM guest271314 <guest271314 at gmail.com>
> wrote:
>
>> JS numbers are specified to be in terms of IEEE-754 doubles, so tenths,
>>> hundredths, and so on cannot be precisely represented. [1] So there is no
>>> way to increase precision here beyond the above that Tab showed, assuming
>>> each of those operations are accurate to the bit.
>>
>>
>> Not sure what the message is trying to convey?  The code at the first
>> post already overcomes the issue of
>>
>>     i % 1 // 0.5670000000000073
>>
>> described by Tab. All of the input numbers are converted to array then
>> back to number without losing any precision or adding more numbers to the
>> input.
>>
>> The proposal suggests that each discrete digit of any number a user can
>> get and set and be clearly defined with a consistent name, or reference.
>> Converting the number to an array is a simple means of processing each
>> digit independently.
>>
>> On Mon, Mar 11, 2019 at 10:41 AM Isiah Meadows <isiahmeadows at gmail.com>
>> wrote:
>>
>>> JS numbers are specified to be in terms of IEEE-754 doubles, so tenths,
>>> hundredths, and so on cannot be precisely represented. [1] So there is no
>>> way to increase precision here beyond the above that Tab showed, assuming
>>> each of those operations are accurate to the bit.
>>>
>>> [1]:
>>> https://www.exploringbinary.com/why-0-point-1-does-not-exist-in-floating-point/
>>> On Sun, Mar 10, 2019 at 13:26 guest271314 <guest271314 at gmail.com> wrote:
>>>
>>>> So this would help with precision?
>>>>
>>>>
>>>> To an appreciable degree, yes, without the scope of JavaScript
>>>> floating-point number implementation.
>>>>
>>>> The gist of the proposal is to formalize, standardize, or whatever term
>>>> specification writers want to use, the *naming* of each method or operation
>>>> which can get and set each discrete digit of a number - without using
>>>> String methods.
>>>>
>>>> For input
>>>>
>>>>     1234.567
>>>>
>>>> Each digit has a formal name which developers can get and set, whether
>>>> in an array, object or number format.
>>>>
>>>> On Sun, Mar 10, 2019 at 5:17 PM Michael Theriot <
>>>> michael.lee.theriot at gmail.com> wrote:
>>>>
>>>>> So this would help with precision?
>>>>>
>>>>> On Sunday, March 10, 2019, guest271314 <guest271314 at gmail.com> wrote:
>>>>>
>>>>>> (If you really wanted this as an integer, it's not well-founded; .567
>>>>>>> isn't exactly representable as a double, so JS doesn't know that you
>>>>>>> "meant" it to have only three digits after the decimal point, and
>>>>>>> thus
>>>>>>> want 567 as the answer. You'll instead get some very very large
>>>>>>> integer that *starts with* 567, followed by a bunch of zeros,
>>>>>>> followed
>>>>>>> by some randomish digits at the end.)
>>>>>>
>>>>>>
>>>>>> The code at the first post solves that problem.
>>>>>>
>>>>>> But the question is still "what would someone use this information
>>>>>>> for?"
>>>>>>
>>>>>>
>>>>>> That question has been answered several times in the posts above.
>>>>>> This users' motivation was and is the ability to manipulate JavaScript
>>>>>> floating-point numbers  (which could be considered "broken", as you
>>>>>> described above) in order to solve mathematical problems (in this case,
>>>>>> directly calculating the *n*th lexicographic permutation) with the
>>>>>> number or decimal being represented as an array, without having to be
>>>>>> concerned with not getting the same value when the array is converted back
>>>>>> to a number.
>>>>>>
>>>>>> Felipe Nascimento de Moura mentioned several other applications.
>>>>>>
>>>>>> The work has already been done. This proposal is essentially to
>>>>>> standardize the naming conventions. Whether a Number method is used
>>>>>>
>>>>>>     i.getTensMethod
>>>>>>
>>>>>> or an array is used
>>>>>>
>>>>>>    arr["integer"] // 1234
>>>>>>
>>>>>> or an object where values are arrays is used
>>>>>>
>>>>>>     o["fraction"] // .567
>>>>>>
>>>>>> Having mentioned Intl.NumberFormat earlier in the thread, if the
>>>>>> issue devoting resources to a *new *proposal, Intl.NumberFormate can
>>>>>> be extended; e.g. a rough draft in code
>>>>>>
>>>>>>     function formatNumberParts(args) {
>>>>>>       return Object.assign({sign:0, fraction:[0], integer:[0]},
>>>>>> ...args.filter(({type}) => type === "integer" || type === "fraction" ||
>>>>>> type === "minusSign").map(({type, value}) => ({[type === "minusSign" ?
>>>>>> "sign" : type]: type !== "minusSign" ? [...value].map(Number) : -1})));
>>>>>>     }
>>>>>>
>>>>>>     let number = -123;
>>>>>>
>>>>>>     let formatter = new Intl.NumberFormat('en-US');
>>>>>>
>>>>>>     let res = formatter.formatToParts(number);
>>>>>>
>>>>>>     formatNumberParts(res);
>>>>>>
>>>>>> If the concern is that the proposal would not be useful, consider
>>>>>> what you would *name* various uses of Math.trunc and remainder
>>>>>> operator used at your message?
>>>>>>
>>>>>>
>>>>>> On Sun, Mar 10, 2019 at 3:58 PM Tab Atkins Jr. <jackalmage at gmail.com>
>>>>>> wrote:
>>>>>>
>>>>>>> On Sat, Mar 9, 2019 at 11:10 AM Felipe Nascimento de Moura
>>>>>>> <felipenmoura at gmail.com> wrote:
>>>>>>> >
>>>>>>> > Personally, I don't think it would be THAT useful...
>>>>>>> > but...I think there is something behind this proposal that makes
>>>>>>> sense.
>>>>>>> >
>>>>>>> > I do believe it could be useful for developers to have an easier
>>>>>>> access to number parts or characteristics.
>>>>>>> > Perhaps something like:
>>>>>>> >
>>>>>>> > const i = 1234.567;
>>>>>>>
>>>>>>> Can you provide a scenario in which these would do something useful,
>>>>>>> such that it would be worth adding them over just using the math
>>>>>>> operations that already exist?
>>>>>>>
>>>>>>> > console.log( i.float ); // 567
>>>>>>>
>>>>>>> i % 1
>>>>>>>
>>>>>>> (If you really wanted this as an integer, it's not well-founded; .567
>>>>>>> isn't exactly representable as a double, so JS doesn't know that you
>>>>>>> "meant" it to have only three digits after the decimal point, and
>>>>>>> thus
>>>>>>> want 567 as the answer. You'll instead get some very very large
>>>>>>> integer that *starts with* 567, followed by a bunch of zeros,
>>>>>>> followed
>>>>>>> by some randomish digits at the end.)
>>>>>>>
>>>>>>> > console.log( i.abs ); // 1234
>>>>>>>
>>>>>>> Math.trunc(i)
>>>>>>>
>>>>>>> > console.log( i.thousands ); // 1
>>>>>>>
>>>>>>> Math.trunc(i / 1000)
>>>>>>>
>>>>>>> > console.log( i.million ); // 0
>>>>>>>
>>>>>>> Math.trunc(i / 1e6)
>>>>>>>
>>>>>>> > console.log( i.hundred ); // 2
>>>>>>>
>>>>>>> Math.trunc(i / 100) % 10
>>>>>>>
>>>>>>> > console.log( i.hundreds ); // 12
>>>>>>>
>>>>>>> Math.trunc(i / 100)
>>>>>>>
>>>>>>> > console.log( i.ten ); // 2
>>>>>>>
>>>>>>> Math.trunc(i / 10) % 10
>>>>>>>
>>>>>>> > console.log( i.tens ); // 123
>>>>>>>
>>>>>>> Math.trunc(i / 10)
>>>>>>>
>>>>>>> > console.log( i.tenth ); // 5
>>>>>>>
>>>>>>> Math.trunc(i % 1 * 10) % 10
>>>>>>>
>>>>>>> > console.log( i.tenths ); // 5
>>>>>>>
>>>>>>> Math.trunc(i % 1 * 10)
>>>>>>>
>>>>>>> > console.log( i.hundredth ); // 6
>>>>>>>
>>>>>>> Math.trunc(i % 1 * 100) % 10
>>>>>>>
>>>>>>> > console.log( i.hundredths ); // 56
>>>>>>>
>>>>>>> Math.trunc(i % 1 * 100)
>>>>>>>
>>>>>>>
>>>>>>> Some of these are easy to remember and use; others take some thinking
>>>>>>> to deploy. But the question is still "what would someone use this
>>>>>>> information for?", such that the benefit to developers is worth the
>>>>>>> cost to all parties involved (spec writers, implementors, testers,
>>>>>>> and
>>>>>>> then developers having to navigate a larger stdlib).
>>>>>>>
>>>>>>> ~TJ
>>>>>>> _______________________________________________
>>>>>>> es-discuss mailing list
>>>>>>> es-discuss at mozilla.org
>>>>>>> https://mail.mozilla.org/listinfo/es-discuss
>>>>>>>
>>>>>> _______________________________________________
>>>>> es-discuss mailing list
>>>>> es-discuss at mozilla.org
>>>>> https://mail.mozilla.org/listinfo/es-discuss
>>>>>
>>>> _______________________________________________
>>>> es-discuss mailing list
>>>> es-discuss at mozilla.org
>>>> https://mail.mozilla.org/listinfo/es-discuss
>>>>
>>> _______________________________________________
>> es-discuss mailing list
>> es-discuss at mozilla.org
>> https://mail.mozilla.org/listinfo/es-discuss
>>
>
>
> --
> Jeremy Martin
> 661.312.3853
> @jmar777 <https://twitter.com/jmar777> / @j <https://stream.live/j>
>
> _______________________________________________
> es-discuss mailing list
> es-discuss at mozilla.org
> https://mail.mozilla.org/listinfo/es-discuss
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20190311/d1ea0f38/attachment-0001.html>


More information about the es-discuss mailing list