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

When dividing 2 integers, an integer is returned instead of a float #43711

Closed
fracteed opened this issue Nov 20, 2020 · 10 comments
Closed

When dividing 2 integers, an integer is returned instead of a float #43711

fracteed opened this issue Nov 20, 2020 · 10 comments
Labels

Comments

@fracteed
Copy link

Godot version:
current master 4.0

Issue description:
When dividing 2 integers, an integer is returned instead of a float. The only way around it is to add type hinting or decimal points.

Steps to reproduce:

for example:

var x = 10
var y = 4
print(x/y)

returns a 2

var x = 10.0
var y = 4.0
print(x/y)

correctly returns a 2.5

var x: float = 10
var y: float = 4
print(x/y)

also correctly returns a 2.5

@mrjustaguy
Copy link
Contributor

This is expected behavior. Int/Int=Int, Float/Float=Float. do print(float(x)/float(y)) to get 2.5 from those 2 ints.

@akien-mga
Copy link
Member

That's always been the case in Godot indeed, or in C/C++ and many similar languages.

If you want a float as return, at least one of the operands has to be a float. Otherwise you get an integer division (faster, truncates).

@fracteed
Copy link
Author

fracteed commented Nov 20, 2020

This worked fine in 3.2 without any type hinting. Has this changed for 4.0 or recently in a 3.2.4 build?
Ah actually now that I think about it, this project was originally done in 3.0.6, so I guess it changed a while back. Anyway, now I know!

@akien-mga
Copy link
Member

akien-mga commented Nov 20, 2020

I can guarantee that 10/4 would return 2 in any Godot version since Godot 1.0 (or more likely since the first open source commit) :)

Here's Godot 2.0:
Screenshot_20201120_090909

@akien-mga
Copy link
Member

To clarify, you don't have to use type hints, but you do have to use a decimal point to let GDScript know that your Variant is a float and not an integer.

Most likely your code had this bug unnoticed all along, or you had one term somewhere in the equation with type float.

@fracteed
Copy link
Author

I just went back and checked this code in 3.2.4 and 4.0, as this was the source of the bug that I was trying to replicate.

In 3.2.4 I had:

var aspect_ratio = get_viewport().get_size().x/get_viewport().get_size().y
print(aspect_ratio)

and this would give 1.777778 (when my res is 1280 x 720)

whereas if I tried that in 4.0 it only gives a result of 1. I got around it by type hinting, but that code did give me a float in return, not an int as in 4.0. So something has changed between 3.2.4 and 4.0 with that particular bit of code.

Also if I do this in 4.0:

var v = Vector2(1280, 720)
print(v.x/v.y)

it does return 1.777778

@akien-mga
Copy link
Member

akien-mga commented Nov 20, 2020

Vector2 components are floats: https://docs.godotengine.org/en/latest/classes/class_vector2.html

Godot 4.0 introduces Vector2i, which as integer coordinates: https://docs.godotengine.org/en/latest/classes/class_vector2i.html

And indeed Viewport.size in Godot 4.0 returns Vector2i as the viewport size is always whole numbers, and thus better represented by integers.

It's important to understand that 1280 is not always an int or always a float, GDScript has type coercion which means that the parser can coerce a type into a compatible type for the holding variable.

In Vector2(1280, 720), 1280 is an "int" but since Vector.x is of type float, it's coerced to a float.
In var i = 1280, 1280 is an int and i is a Variant, which can hold int values, so i is an int.
In var f : float = 1280, 1280 is an int, f is a float (type hint), so the value is coerced to a float.
In var f = 1280.0, 1280.0 is a float (decimal point), f is a Variant, which can hold float values, so f is a float.
In var i : int = 1280.0, 1280.0 is a float (decimal point), i is an int (type hint), so narrowing conversion will happen (float converted to int, with potential loss of information), so GDScript will give you a warning: "Narrowing conversion (float is converted to int and loses precision)."

@akien-mga
Copy link
Member

akien-mga commented Nov 20, 2020

In your specific case, the only issue is thus the introduction of an integer version of Vector2, which is used by Viewport.size. You now have to do e.g. var aspect_ratio = float(get_viewport().get_size().x) / get_viewport().get_size().y, or

var size : Vector2 = get_viewport().get_size()   # Note: this is type coercion too, from Vector2i to Vector2.
var aspect_ratio = size.x / size.y

It can be debated whether changing Viewport.size to a Vector2i is worth the additional step needed to calculate an aspect ratio using it, but there's no problem at the language level.

@fracteed
Copy link
Author

Ah, thanks for the explanation! At least I know I wasn't going crazy, as I had no idea about Vector2i in Godot 4 and that Viewport.size was returning it. All makes sense now. This is what I get for trying to do some gamedev on a prealpha build :)

@aaronfranke
Copy link
Member

@fracteed In your particular case, you should use .aspect().

var aspect_ratio = get_viewport().get_size().aspect()
print(aspect_ratio)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

4 participants