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

Behavior of String::num causes parse error for large float fields in Godot inspector #93768

Open
MrEgggga opened this issue Jun 30, 2024 · 7 comments

Comments

@MrEgggga
Copy link

Tested versions

  • Reproducible in 3.5.3.stable.official, 4.2.1.stable.official, 4.3.beta (4ab8fb8)

System information

Godot v4.3.beta (4ab8fb8) - macOS 14.0.0 - GLES3 (Compatibility) - Apple M1 - Apple M1 (8 Threads)

Issue description

  • Entering a float in plain decimal notation greater than the maximum signed integer into a float field in the inspector causes an error and sets the field to the maximum signed 64-bit integer instead -- this is a separate issue relating to GDScript's way of parsing floats.
  • It's possible to enter large values into float fields in the inspector using scientific notation (e.g. by typing 1e100 into the field), but when clicking off the field this is converted into a long series of digits (e.g. 10000000000000000159028911097599180468360808563945281389781327557747838772170381060813469985856815104). This is stored properly.
  • If you click back into the field and then back off, the field tries to parse its current text (a sequence of digits larger than the maximum signed 64-bit integer), throws an error, and sets the field to a float representation of the maximum signed 64-bit integer.

I assume a similar thing would happen with SpinBox, but I haven't tested this.

All of the individual steps of this (error for parsing absurdly large strings of digits; stringifying a float as a series of digits) make a lot of sense, but the result is that clicking on and off of a field changes the value, which feels like a bug.

I can think of a few possible solutions:

  • Show absurdly large numbers in the inspector with scientific notation -- this has the advantage of being human-readable and gdscript-parseable and there seems to be a way of stringifying floats using scientific notation seeing as that's how large floats seem to be stored in the save file format. However, this seems like more of a new feature than a bugfix.
  • Fix the way GDScript parses floats.
  • Change something about how EditorSpinSlider works so that clicking on and off of something never changes its value.

Steps to reproduce

  1. Create a script with an exported float field (no range hint).
  2. In the inspector, click on the field and type in 1e+100.
  3. Click off of the field to confirm. The field should now say 10000000000000000159028911097599180468360808563945281389781327557747838772170381060813469985856815104.
  4. Click on the field again to edit it. Don't type anything.
  5. Click off of the field. An error should show in the Output section, and the field is set to 9223372036854775807.

Minimal reproduction project (MRP)

float-bug.zip
(v4.2.1.stable.official, I think)

@MrEgggga
Copy link
Author

Theoretically speaking, there would also be the same problem on the smaller end, but maybe a bit less dramatic -- a value of 1e-50, for example, would be successfully stored, stringified as 0, and then clicking on and back off of the field would set the field to zero. Practically speaking, however, this would never come up because float fields are already rounded to the nearest thousandth by default for whatever reason.

Also: I don't think this issue is very important.

@RicardRC
Copy link
Contributor

RicardRC commented Jul 1, 2024

It is important to me, doing a somewhat detailed space simulator, I need to enter values that routinely vary between e21 and e-21 pretty commonly for orbital calculation values and other math related values. And I care for the significant digits that I entered, even if they are after 18 zeroes behind a comma. This issue entirely prevents me from using the inspector, and at this point, the resource type for my custom resources becomes entirely unusable from the editor point of view. I have to resort to an external database for this. What bugs me is that while the ball bounces around while trying to cover every case with a magic solution, years pass by and not much changes, instead of just providing a toggle somewhere in the config or an annotation to the variable that just allows to switch between dumbed down floats for inspector or actual computer floats. I'd be happy even if accurate floats does not even have a slider with steps. Just allow us to write down valid floats, and keep them safe, that's pretty much it.

@Zireael07
Copy link
Contributor

I have a similar use case, I use CSV for said data. Of course this means it's no longer editable in the inspector

@MrEgggga
Copy link
Author

MrEgggga commented Jul 1, 2024

I think the best solution is to use scientific notation for fields in the inspector, either by default or optionally with a hint. There is a function String::num_scientific which could be used for this purpose, but there might be issues involving fields stored as single-precision floats. I'm planning to start or find an existing proposal for this, but it won't work on the finer end of things until godotengine/godot-proposals#3524 is implemented.

@aaronfranke
Copy link
Member

aaronfranke commented Dec 5, 2024

Entering a float in plain decimal notation greater than the maximum signed integer into a float field in the inspector causes an error and sets the field to the maximum signed 64-bit integer instead

This is a bug indeed - if it's not a valid integer, it should try again as a float, especially since the field accepts floats. It seems that currently it uses TextServer::parse_number, CC @bruvzg.

when clicking off the field this is converted into a long series of digits

And I care for the significant digits that I entered, even if they are after 18 zeroes behind a comma.

This is expected behavior, this happens due to the limitations of 64-bit floats. You can't reliably store an integer with a hundred digits in a 64-bit float. In fact, the limit is 2^53, so you can't even store 18 digits, you only get 15.95 decimal digits (almost 16 digits).

If you click back into the field and then back off, the field tries to parse its current text (a sequence of digits larger than the maximum signed 64-bit integer), throws an error, and sets the field to a float representation of the maximum signed 64-bit integer.

This is fixed by #47502, since now floats are converted to string using float literals.

I think the best solution is to use scientific notation for fields in the inspector

That's a good idea, but we should wait until after the scientific notation function is fixed: #98750

@bruvzg
Copy link
Member

bruvzg commented Dec 5, 2024

It seems that currently it uses TextServer::parse_number

Should not be related. parse_number only work with strings (string in, string out), and used to convert it to other type of symbols used to represent digits (e.g, Eastern Arabic). This function has no idea if it's float or int (or valid number at all), and can work with arbitrary length. So whatever is responsible is probably right before parse_number call.

@RicardRC
Copy link
Contributor

RicardRC commented Dec 6, 2024

This is expected behavior, this happens due to the limitations of 64-bit floats. You can't reliably store an integer with a hundred digits in a 64-bit float. In fact, the limit is 2^53, so you can't even store 18 digits, you only get 15.95 decimal digits (almost 16 digits).

I'm not asking to be able to store 3,0000000000000000000000000000000054, this would be unreasonable and not at all what I said. I;m asking to be able to store 0,0000000000000000000000000000000054. Which is storing 2 digits, after lots of zeroes. Which is the floating part about floating point, absolutely doable in a double.
Quoting wikipedia on double float precision: "The 11 bit width of the exponent allows the representation of numbers between 10−308 and 10308, with full 15–17 decimal digits precision.". I just need to store 1.35 e22 or 2.54 e-21, and have the editor treat them consistently. If a type hint is needed, nice, I will use that. I'm not necesarily advocating for an automatic solution for every use case and a slider at the same time.

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

6 participants