Skip to content

"123 fahrenheit" -> TypeError: Cannot implicitly convert a number with >15 significant digits to BigNumber #3450

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

Closed
keras opened this issue Apr 7, 2025 · 4 comments
Labels

Comments

@keras
Copy link

keras commented Apr 7, 2025

The issues section is used only for bug reports. Please use the Discussions section to ask questions and share ideas and suggestions.

Describe the bug
evaluate("123 fahrenheit") using BigNumbers results an error:

TypeError: Cannot implicitly convert a number with >15 significant digits to BigNumber

I'm using mathjs v14.4.0

I see this might be similar to #1269 which resulted in a bug fix.

To Reproduce

mathjs.create(mathjs.all, {number: 'BigNumber', precision: 64})
  .evaluate("123 fahrenheit")

Uncaught TypeError: Cannot implicitly convert a number with >15 significant digits to BigNumber (value: 0.5555555555555556). Use function bignumber(x) to convert to BigNumber.
@josdejong
Copy link
Owner

Thanks for reporting, this may indeed be similar to #1269.

Help fixing this bug would be very welcome!

@gwhitney
Copy link
Collaborator

gwhitney commented Apr 9, 2025

This is almost certainly the result of a combination of two design decisions currently in mathjs:

(1) the Unit class eagerly converts values into the standard unit for each dimension, rather than lazily doing so; I think the standard unit is kelvin in the case of temperatures. This design decision already causes other problems, for example with exact values of sin and cos when using angles in units of degrees or cycles, cf. #3381, and I personally think should be revisited and changed.

(2) the conversion from number to bignumber does not detect and respect exact rational numbers, which causes many problems; there is a thorough discussion of this in #1485, among other places. Again, I have argued that this decision should be revisited and changed.

I think what is happening is that the conversion from fahrenheit to kelvin involves a denominator of 9, which cannot be exactly represented in either base 2 or 10, and therefore the conversion from number to bignumber does not currently recognize the result as an exact number of ninths, and so thinks there is "roundoff error" that it should not promote to the much greater precision of a bignumber.

In the specific case in this issue, I think addressing either (1) or (2) would solve the problem; I don't personally see any great way to deal with it other than one or both of these routes. Therefore I have removed the "help wanted" label, as the only paths I see to dealing with this are to decide what to do on at least one of points (1) and (2). I don't think it's just a matter of "going into the code and fixing the bug", so I am leery of asking for "outside" help on this one.

As it represents a new bad interaction between two known points of pain (hard to say they are outright "bugs"), I am not closing this issue as a duplicate; it is possible there would be some way to prevent this interaction without directly addressing (1) or (2) even though I am not at the moment seeing it.

In the meantime, I believe the workaround of writing unit(123, fahrenheit) will correctly produce a temperature whose internal recorded value (in kelvin) will be exact to bignumber precision. If it's feasible for you to give that a try in your use case, I would be interested in confirmation that it works.

@josdejong
Copy link
Owner

I the immediate issue at hand is related to the automatic conversion between numeric types, which sometimes throws an exception.

In this case, when evaluating "123 fahrenheit" with BigNumber configuration, we basically evaluate math.unit('fahrenheit').multiply(math.bignumber(123)). Internally in Unit.multiply, a temporary numeric value 1 is created which is a number. When consecutively using math.multiplyScalar internally and passing both a BigNumber and a number, the number is converted into a BigNumber, which can throw this exception. Since this is all internal, it is not possible to explictely convert the number into a BigNumber, which is a problem.

Note that implicit type conversions is also discussed right now in #3375.

It feels a bit like a workaround, but what we can do to solve this is create these numeric 1 with the same type as the value that we're multiplying (or dividing). I created a PR showing that approach in #3454. Now, we do need a more fundamental solution to this issue, but for the time being I think it's a good workaround. @gwhitney can you have a look at this PR please?

@gwhitney
Copy link
Collaborator

It feels a bit like a workaround, but what we can do to solve this is create these numeric 1 with the same type as the value that we're multiplying (or dividing). I created a PR showing that approach in #3454. Now, we do need a more fundamental solution to this issue, but for the time being I think it's a good workaround. @gwhitney can you have a look at this PR please?

I agree it's a bandage rather than a therapy, but perhaps you prefer a bandage for now. I will take a look.

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

No branches or pull requests

3 participants