Closed Kolterdyx closed 4 months ago
A solution I came up with is a decimal type which stores numbers similarly to how computers store floats, but in base10. The format is Mantissa * 10^Exponent. Both the mantissa and exponent can be stored in separate scoreboards.
All operations (addition, multiplication, division) can be implemented for this type.
The mantissa scoreboard could use 9 of its digits for the mantissa, and the exponent could use all 2^32 values for the exponent.
For example, if the mantissa scoreboard is 125_000_000 and exponent scoreboard is 0, the number is 1.25. Bring the exponent to 1, the number becomes 12.5. Bring it to -1, the number becomes 0.125. The mantissa could always use 9 digits for consistency, so a mantissa of 70_000_000 would be invalid.
Max value for the exponent could indicate the infinity value, and a mantissa outside of the range ±999_999_999 could be used as NaN.
Reading numbers into this type would require string parsing unfortunately, so each data retrieval operation would be expensive.The disadvantage is that each operation on this type takes a bunch of commands and may not be performance efficient, but it does represent floats very well.
Since this is already a statically typed language, I guess we could split up the number
type into multiple types, and have two versions of the floating point number, and the user can decide which type to use depending on the drawbacks of each one. I don't think it would add much complexity to the compilation either
Even though fixed point numbers have been added, I'll keep this issue open for further discussion so anyone can comment on this.
I'll also mention that there is no way read a floating point value from Minecraft NBT storage. You can display it with the data command, but the value returned to other commands is rounded down for some reason. Apparently this is intended behaviour, which sucks, so good floating point arithmetic will not be possible for a long time without implementing a custom data type and operating with it, which will be both cumbersome an inefficient
Actually, now that I think about it, it's probably best to start a new issue
The current arithmetic operators' implementation uses scoreboards for operating on numbers. scoreboards only support integers, which means that floating point numbers will be rounded before performing any operation.
As far as I know, the only floating point operation available is the scale parameter in the
execute store storage <storage> <path> <type> <scale>
command. This allows for floating point multiplication up to double precission, but that is about the only direct path available. Division could be accomplished by multiplying by a less than 1 scalar, but that just moves the problem further because we still need to figure out how to compute1/x
somehow without knowing the value ofx
at compile time.Off the top of my head, a plausible solution would be to multiply the number by a constant order of magnitude, perform an integer operation, and then divide by the inverse of the constant. It would look soomething like this:
This kinda works, but has the issue that you can only have as much precision as you shift digits left. If your desired decimal precision is
x
, you would have to scale up and then down numbers by a factor of10^x
, which limits a lot our precision and can cause trouble with large numbers for large values ofx
.Any other ideas are welcome