Kolterdyx / mcbasic

A custom scripting language for generating complex Minecraft datapacks
GNU General Public License v3.0
0 stars 0 forks source link

Support for floating point arithmetic #1

Closed Kolterdyx closed 4 months ago

Kolterdyx commented 4 months ago

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 compute 1/x somehow without knowing the value of x 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:

PRECISION = 1000
INV_PRECISION = 0.001
x = 3.14159265359
y = 1.76

# We are going to compute x/y

# scale only the numerator up
num = x * PRECISION # 3145.9265359
den = y
# perform integer operation, with the scoreboard command
tmp = num // den # 1787
# scale the result by the inverse of our precision value, which as we know at compile time, we can just hardcode
result = tmp * INV_PRECISION # 1.787

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 of 10^x, which limits a lot our precision and can cause trouble with large numbers for large values of x.

Any other ideas are welcome

WOODEN-CHEST commented 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.

Kolterdyx commented 4 months ago

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

Kolterdyx commented 4 months ago

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

Kolterdyx commented 4 months ago

Actually, now that I think about it, it's probably best to start a new issue