Weird float math

My code instead of adding by 0.05 or removing its causing stuff to go weird
image

	manage.ClickDetector.MouseClick:Connect(function(plr)
		if plr.Team.Name == "King" then
			stand.Pay.Value = stand.Pay.Value + 0.05
			Messager.Notify(plr, "Raised the pay to " .. tostring(stand.Pay.Value), Color3.new(0,0,0))
		else
			Messager.Notify(plr, "YOU NEED TO BE KING TO DO THIS", Color3.new(0,0,0))
		end
	end)
	manage.ClickDetector.RightMouseClick:Connect(function(plr)
		if plr.Team.Name == "King" then
			if stand.Pay.Value ~= 0 then
				stand.Pay.Value = stand.Pay.Value - 0.05
				
				Messager.Notify(plr, "Lowered the pay to " .. tostring(stand.Pay.Value), Color3.new(0,0,0))
			else
				Messager.Notify(plr, "IT CANT GO UNDER 0", Color3.new(0,0,0))
			end
		else
			Messager.Notify(plr, "YOU NEED TO BE KING TO DO THIS", Color3.new(0,0,0))
		end
	end)
	

floats can’t always represent human numbers exactly

So they approximate them

tostring shows you that approximation

Use string.format("%.2f", stand.Pay.Value) to control exactly how it’s formatted

1 Like

That’s actually normal for floating point types. The IEEE 734 standard has the breakout of the machine word (32-bit or 64-bit) floating point numbers. The issue is the mantessa itself. The most significant bit, when set, adds 0.5 to the value, then the next bit is 0.25, next is 0.125, and so on. It’s because 0.05 cannot be represented exactly by power of 2 floating point representation. Your best bet would be to do this:

stand.Pay.Value = math.round((stand.Pay.Value * 100) - 5) / 100

This shifts the decimal point two places to the right, subtracts 5, then shifts it back 2 places to the left. If you are looking to display it, then do this:

.. tostring(math.round(stand.Pay.Value * 100) / 100)

EDIT:

To be honest, @nicemike40 has a better solution for displaying it. If you are familiar with C at all, string.format is basically like sprintf in C. But for the format, I would use “%0.2f” instead because if the value goes less than 1, it will print a leading 0 before the decimal point.

You can read more about string.format here in the Roblox documentation.

While your explanation of the problem is awesome, rounding the number will not always work—string.format gives you precise control

I would recommend doing what @nicemike40 said..
However the issue is that

string.format("%.2f", stand.Pay.Value)

would always give the number 2 zeros at the end
Example:

Raised the pay to 1.00
Raised the pay to 1.15
Raised the pay to 1.20

If you wish to not do that then use the following function to round the number

local function round(x)
    local precision = 2
    local r = 10^precision

    return math.floor(x*r+0.5)/r
end

Yeah, I forgot about string.format even though I used it myself. I updated my answer to reflect that the OP should use your solution to display, with a modification.

just nitpicking here, but these are the same

print(string.format("%.2f", 0.1))  --> 0.10
print(string.format("%0.2f", 0.1)) --> 0.10

you’re probably thinking of something like this?

print(string.format("%06.2f", 0.1)) --> 000.10

No. Perhaps string.format adds a 0 automatically to floats that are < 1. But in C, you have to actually specify it.

Why use math.floor instead of math.round?

There’s no particuliar reason to that.

Just saying, less calculations = better performance. Probably insignificant, but also it’s less code to type return math.round(x*r)/r

I believe that math.round is

function math.round(x)
   return math.floor(x+0.5)
end

Or

function math.round(x)
   return math.exp(x-0.5)
end

And you are certainly right about the less code part

There is an actual math.round function that was added a while ago as shown in the math listings.