godot icon indicating copy to clipboard operation
godot copied to clipboard

String to float doesn't work as expected

Open bashcole opened this issue 4 years ago • 3 comments

Godot version: v3.2.3.stable.official

Issue description: After creating a number from a string that number doesn't equal itself

Steps to reproduce:

# 1. Multiple values comparison test
var tests = [
	["1.3", 1.3],
	["1.23", 1.23],
	["1", 1]
]

for test in tests:
	var num = float(test[0])
	
	if num == test[1]:
		print(str(test[0]) + " and " + str(test[1]) + " are equal") # only 1 will be equal
	else:
		print(str(test[0]) + " and " + str(test[1]) + " are not equal") # 1.23 and 1.3 will not be equal


# 2. Checking for a whole number
var string = "1.3" # 1.3
var number = float(string) * 10 # 13

if fmod(number, 1) == 0.0:
	print("whole number")
else:
	print("not whole number because the result is: ", fmod(number, 1)) # 1 instead of 0
	

# 3. Simple comparison test
var extra_string = "1.3" # 1.3
var extra_number = float(extra_string) * 10 # 13

if extra_number == 13:
	print("expected")
else:
	print("not expected")

I also tested the #3 test using php and I got the expected behavior.

My main use case is to find if the number is whole or not. I understand that I can compare float using a method like this

const FLOAT_EPSILON = 0.00001

static func compare_floats(a, b, epsilon = FLOAT_EPSILON):
    return abs(a - b) <= epsilon

bashcole avatar Dec 31 '20 10:12 bashcole

You can't accurately represent 1.3 and 1.23 as a FP numbers and thus 1.3 * 10 != 13. Use is_equal_approx to compare FP numbers (as you suggested yourself).

To demonstrate that precision is the issue:

extends MainLoop

func _init():
	print(float("1.3") * 10 == 13.0)
	print(float("1.25") * 10 == 12.5)

Output:

False
True

Demindiro avatar Dec 31 '20 14:12 Demindiro

Godot 3.2.3.stable.official using PopOS 20.10.

I was going to open a new issue, but decided to do it here instead. There seems to be some sort of misbehaviour when converting floats to strings. Somehow it sometimes works as expected but sometimes it doesn't. Just in case, I'm not talking about comparing them, I'm talking about the value that gets displayed.

var cast_f : float = float('4.99')
var convert_f : float = str2var('4.99')

print(cast_f, ' - ', convert_f)
print(cast_f * 10, ' - should be 49.9')
print(convert_f * 10, ' - should be 49.9')

prints:

4.99 - 4.99 49.899998 - should be 49.9 49.9 - should be 49.9

vicguedez avatar Jan 11 '21 20:01 vicguedez

I was going to open a new issue, but decided to do it here instead. There seems to be some sort of misbehaviour when converting floats to strings. Somehow it sometimes works as expected but sometimes it doesn't. Just in case, I'm not talking about comparing them, I'm talking about the value that gets displayed.

In Godot 4, this is no longer an issue. It seems like internally the accuracy of floats for the intents of the visualization has been upgraded to use 64 bits, matching the float Variant type. image

Regarding this original proposal, those kind of situations may be less common as a result of this. Not sure it's worth writing "Use is_equal_approx"one more time in the otherwise unrelated conversion method. Maybe?

Mickeon avatar Dec 05 '22 19:12 Mickeon