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

Should we allow int*float and int*decimal? #261

Closed
jclark opened this issue Jul 21, 2019 · 17 comments
Closed

Should we allow int*float and int*decimal? #261

jclark opened this issue Jul 21, 2019 · 17 comments
Assignees
Labels
design/dislike Do not like something about the design implementation/inprogress Implementation inprogress lang Relates to the Ballerina language specification sl-update-priority Priority for Swan Lake Updates status/pending Design is agreed and waiting to be added

Comments

@jclark
Copy link
Collaborator

jclark commented Jul 21, 2019

One could view 3 * 3.5 as meaning to 3.5 + 3.5 + 3.5. In other words multiplication of a float by an int is an operation on a float, which is distinct from multiplication of two floats and which does not need to be viewed as requiring a conversion from int to float.

For example, imagine that we represent a time duration as decimal seconds.

type Duration decimal;
const Duration SECOND = 1; // OK: contextually expected type is decimal
// this is not allowed currently: decimal * int
const Duration HOUR = 60*SECOND;
@jclark jclark added lang Relates to the Ballerina language specification design/dislike Do not like something about the design labels Jul 21, 2019
@jclark jclark added this to the 2019R3 milestone Jul 21, 2019
@jclark jclark self-assigned this Jul 21, 2019
@hasithaa
Copy link
Contributor

+1 for the Suggestion. Right now there is an ambiguity when we use numeric literals (1) vs variable reference (2).

eg:

decimal a = 10.1;
decimal b = a * 10; // (1) Working 

int c = 10;
decimal d = a * c; // (2) Not allowed.

(1) works because Spec says,

A numeric-literal represents a value belonging to one of the basic types int, float or decimal. The basic type to which the value belongs is determined as follows:

- if the numeric-literal includes a FloatTypeSuffix, then the basic type is float;
- if the numeric-literal includes a DecimalTypeSuffix, then the basic type is decimal;
- if the numeric-literal is a HexFloatingPointLiteral, then the basic type is float;
- otherwise, the basic type depends on the applicable expected numeric type (where the possible basic types are int, float and decimal):
-- if the applicable contextually expected type is a subtype of decimal, then the basic type is decimal;
-- if the applicable contextually expected type is a subtype of float, then the basic type is float;
-- otherwise, if the numeric literal is an int-literal, then the basic type is int;
-- otherwise, the basic type is float.

@jclark
Copy link
Collaborator Author

jclark commented Jul 22, 2019

I agree (1) should work, but I think spec needs to be clearer about this. If expression E is E1*E2, and the contextually expected type for E is decimal, then the contextually expected type for both E1 and E2 should also be decimal, but I don't see anything in the spec that says this.

@jclark jclark added this to the Swan Lake Update 1 milestone Feb 15, 2022
@jclark
Copy link
Collaborator Author

jclark commented Feb 17, 2022

Similarly float/int, decimal/int. Think about remainder also.

@hasithaa
Copy link
Contributor

hasithaa commented Mar 8, 2022

int i = 5;
float f = 25.0;
decimal d = 10;

int a1 = f/i;  // (1)
float a2 = f/i;  // (2)

int a3 = d/i; // (3)
decimal a4 = d/i; // (4)

int a5 = f*d; // (5) weird, but should be OK.
float a6 = i*d // (6)
decimal a7 = i*f; // (7)

var v1 = f/i; // type is float (8)
var v2= d/i; // type is decimal (9)
var v3= d/f; or f/d; type is float, not decimal. (10)

Technically, we can support all the above cases.

@jclark
Copy link
Collaborator Author

jclark commented Mar 8, 2022

There is no use of the contextually expected type to determine the operation. The operation is determined by the type of the operands.

We are not changing the language to do implicit numeric conversions.

d*i (or i*d) is conceptually an operation on decimal i.e. repeated addition. The result is a decimal. Similarly, d/i is is the inverse of d*i: divide up the d into i equal parts. This is a decimal operation and the result is a decimal.

The only ones in your list that this issue covers are: 2, 4, 8, 9.

@jclark jclark added the implementation/inprogress Implementation inprogress label Mar 8, 2022
@SandaruJayawardana
Copy link
Contributor

Related to int*float feature..
here, we are going to calculate int*float by simply adding up float numbers because ballerina does not support implicit casting rule is still there (comment)
Since we cannot do (practically) the summation of floating number up to the value of int, we are hoping to do the type casting internally (cast the integer into float) and do the multiplication right?
If we do so, my opinion is, we are violating the ballerina rule (no implicit cast).

For an example
Let's get the float64 representation for the 0.1, the actual value is 1.00000000000000005551115123126E-1
so if we are supposing to do the multiplication using summation, we should use this actual value to sum up right?
If we simply do the floating multiplication, seems it will use higher precision during the calculation and convert the final results back to float.
In java,

double f = 0.1;
double i = 100000;
f = i * f;
System.out.println(f);  // 100000
        
double f2 = 0;
for (int k = 0; k < 100000; k++) {
    f2 += 0.1;
}
System.out.println(f2); // 10000.000000018848 probably this is not the result user expected

@jclark
Copy link
Collaborator Author

jclark commented Mar 24, 2022

You would implement int*float by converting the int to a float and doing a float multiplication. Similarly for decimal.

@SandaruJayawardana
Copy link
Contributor

If so, ballerina supports implicit numeric conversions for int -> float and int -> decimal?

@jclark
Copy link
Collaborator Author

jclark commented Mar 24, 2022

Do you have a question about how to implement this feature?

@SandaruJayawardana
Copy link
Contributor

Do you have a question about how to implement this feature?

Ah no.

I was confused about followings..

We are not changing the language to do implicit numeric conversions.

You would implement int*float by converting the int to a float and doing a float multiplication. Similarly for decimal.

IINM, we don't need to change the language to do implicit numeric conversions, because we are assuming 3 * 3.5 == 3.5 + 3.5 + 3.5. But it is not true with float64 according to comment, isn't it?

@rdulmina
Copy link
Contributor

I think considering decimal * int as repetitive addition of decimal is just a concept right?. So it does not need 3 * 3.5 == 3.5 + 3.5 + 3.5 to be true?

@jclark
Copy link
Collaborator Author

jclark commented Mar 25, 2022

I think considering decimal * int as repetitive addition of decimal is just a concept right?

Right.

@rdulmina
Copy link
Contributor

Are we going to allow int/float and int/decimal also?. And what about mod are we going to allow both int%float and float%int?

@jclark
Copy link
Collaborator Author

jclark commented Apr 5, 2022

No, we are not allowing int/float or int/decimal.

We should float % int and decimal % int.

@rdulmina
Copy link
Contributor

rdulmina commented Apr 7, 2022

Should the following be true?

public function main() {
    int int1 = 19210213213123012;
    int int2 = 110;
    float float1 = 1.211;

    float x1 = int1 * int2 * float1; // 2.5589925021201167E18
    float x2 = int1 * float1 * int2; // 2.5589925021201162E18
    io:println(x1 == x2); // false
}

according to commutative law a + b = b + a and ab = ba order of the operands should not affect the final result. I have tested this with java and golang but they also behave in the same way the jballerina does. So is the above behaviour is correct?

Found some similar scenarios where the jballerina does not preserve commutative law ballerina-platform/ballerina-lang#35706. Should jballerina handle these cases?

@hasithaa
Copy link
Contributor

hasithaa commented Apr 8, 2022

This is happening only for the float type due to the limits of precision. It seems this is common in other languages too. If someone wants exact results, they can use decimal instead of float.

@jclark
Copy link
Collaborator Author

jclark commented Apr 8, 2022

IEEE floating point values are not real numbers and do not follow the laws that apply to real numbers in mathematics. It will happen with decimal too, because that also has precision limits.

It is OK for x1 not to be equal to x2 in the above.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
design/dislike Do not like something about the design implementation/inprogress Implementation inprogress lang Relates to the Ballerina language specification sl-update-priority Priority for Swan Lake Updates status/pending Design is agreed and waiting to be added
Projects
None yet
Development

No branches or pull requests

4 participants