www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Promotion rules ... why no float?

reply Sai <test test.com> writes:
Consider this:

import std.stdio;
void main()
{
	byte a = 6, b = 7;
	auto c = a + b;
	auto d = a / b;
	writefln("%s, %s", typeof(c).stringof, c);
	writefln("%s, %s", typeof(d).stringof, d);
}

Output :
int, 13
int, 0

I really wish d gets promoted to a float. Besides C 
compatibility, any reason why d got promoted only to int even at 
the risk of serious bugs and loss of precision?

I know I could have typed "auto a = 6.0" instead, but still it 
feels like an half-baked promotion rules.
Sep 06 2016
next sibling parent Stefan Koch <uplink.coder googlemail.com> writes:
On Tuesday, 6 September 2016 at 07:04:24 UTC, Sai wrote:
 Consider this:

 import std.stdio;
 void main()
 {
 	byte a = 6, b = 7;
 	auto c = a + b;
 	auto d = a / b;
 	writefln("%s, %s", typeof(c).stringof, c);
 	writefln("%s, %s", typeof(d).stringof, d);
 }

 Output :
 int, 13
 int, 0

 I really wish d gets promoted to a float. Besides C 
 compatibility, any reason why d got promoted only to int even 
 at the risk of serious bugs and loss of precision?

 I know I could have typed "auto a = 6.0" instead, but still it 
 feels like an half-baked promotion rules.
Because implicit conversion to float on every division is bad bad bad.
Sep 06 2016
prev sibling next sibling parent reply Andrea Fontana <nospam example.com> writes:
On Tuesday, 6 September 2016 at 07:04:24 UTC, Sai wrote:
 Consider this:

 import std.stdio;
 void main()
 {
 	byte a = 6, b = 7;
 	auto c = a + b;
 	auto d = a / b;
 	writefln("%s, %s", typeof(c).stringof, c);
 	writefln("%s, %s", typeof(d).stringof, d);
 }

 Output :
 int, 13
 int, 0

 I really wish d gets promoted to a float. Besides C 
 compatibility, any reason why d got promoted only to int even 
 at the risk of serious bugs and loss of precision?

 I know I could have typed "auto a = 6.0" instead, but still it 
 feels like an half-baked promotion rules.
Integer division and modulo are not bugs. Andrea
Sep 06 2016
next sibling parent reply Jonathan M Davis via Digitalmars-d <digitalmars-d puremagic.com> writes:
On Tuesday, September 06, 2016 07:26:37 Andrea Fontana via Digitalmars-d 
wrote:
 On Tuesday, 6 September 2016 at 07:04:24 UTC, Sai wrote:
 Consider this:

 import std.stdio;
 void main()
 {

     byte a = 6, b = 7;
     auto c = a + b;
     auto d = a / b;
     writefln("%s, %s", typeof(c).stringof, c);
     writefln("%s, %s", typeof(d).stringof, d);

 }

 Output :
 int, 13
 int, 0

 I really wish d gets promoted to a float. Besides C
 compatibility, any reason why d got promoted only to int even
 at the risk of serious bugs and loss of precision?

 I know I could have typed "auto a = 6.0" instead, but still it
 feels like an half-baked promotion rules.
Integer division and modulo are not bugs.
Indeed. There are a lot of situations where they are exactly what you want. Floating point adds imprecision to calculations that you often want to avoid. Also, if I understand correctly, floating point operations are more expensive that the corresponding integer operations. So, it would be very bad if dividing integers resulted in a floating point value by default. And if you _do_ want a floating point value, then you can cast one of the operands to the floating point type you want, and you'll get floating point arithmetic. Personally, I find that I rarely need floating point values at all. Another thing to take into account is that you don't normally want stuff like arithmetic operations to do type conversion. We already have enough confusion about byte and short being converted to int when you do arithmetic on them. Having other types suddenly start changing depending on the operations involved would just make things worse. - Jonathan M Davis
Sep 06 2016
parent reply Sai <test test.com> writes:
Thanks for the replies.

I tend to use a lot of float math (robotics and automation) so I 
almost always want float output in case of division. And once in 
a while I bump into this issue.

I am wondering what are the best ways to work around it.

     float c = a / b;     // a and b could be integers.

Some solutions:

     float c = cast!float(a) / b;
     float c = 1f * a / b;


Any less verbose ways to do it?

Another solution I am thinking is to write a user defined integer 
type with an overloaded division to return a float instead and 
use it everywhere in place of integers. I am curious how this 
will work out.
Sep 06 2016
next sibling parent reply Steven Schveighoffer <schveiguy yahoo.com> writes:
On 9/6/16 11:00 AM, Sai wrote:
 Thanks for the replies.

 I tend to use a lot of float math (robotics and automation) so I almost
 always want float output in case of division. And once in a while I bump
 into this issue.

 I am wondering what are the best ways to work around it.

     float c = a / b;     // a and b could be integers.

 Some solutions:

     float c = cast!float(a) / b;
auto c = float(a) / b; -Steve
Sep 06 2016
parent Daniel Kozak via Digitalmars-d <digitalmars-d puremagic.com> writes:
Dne 6.9.2016 v 17:26 Steven Schveighoffer via Digitalmars-d napsal(a):

 On 9/6/16 11:00 AM, Sai wrote:
 Thanks for the replies.

 I tend to use a lot of float math (robotics and automation) so I almost
 always want float output in case of division. And once in a while I bump
 into this issue.

 I am wondering what are the best ways to work around it.

     float c = a / b;     // a and b could be integers.

 Some solutions:

     float c = cast!float(a) / b;
auto c = float(a) / b; -Steve
another solution is use own function for div operation auto c = div(a,b);
Sep 06 2016
prev sibling next sibling parent Daniel Kozak via Digitalmars-d <digitalmars-d puremagic.com> writes:
Dne 6.9.2016 v 17:00 Sai via Digitalmars-d napsal(a):

 Thanks for the replies.

 I tend to use a lot of float math (robotics and automation) so I 
 almost always want float output in case of division. And once in a 
 while I bump into this issue.

 I am wondering what are the best ways to work around it.

     float c = a / b;     // a and b could be integers.

 Some solutions:

     float c = cast!float(a) / b;
     float c = 1f * a / b;


 Any less verbose ways to do it?

 Another solution I am thinking is to write a user defined integer type 
 with an overloaded division to return a float instead and use it 
 everywhere in place of integers. I am curious how this will work out.
Because of alias this it works quite well for me in many cases. However one unplesant situation is with method parameters
Sep 06 2016
prev sibling next sibling parent Andrea Fontana <nospam example.com> writes:
On Tuesday, 6 September 2016 at 15:00:48 UTC, Sai wrote:
 Thanks for the replies.

 I tend to use a lot of float math (robotics and automation) so 
 I almost always want float output in case of division. And once 
 in a while I bump into this issue.

 I am wondering what are the best ways to work around it.

     float c = a / b;     // a and b could be integers.

 Some solutions:

     float c = cast!float(a) / b;
     float c = 1f * a / b;


 Any less verbose ways to do it?

 Another solution I am thinking is to write a user defined 
 integer type with an overloaded division to return a float 
 instead and use it everywhere in place of integers. I am 
 curious how this will work out.
Exotic way: import std.stdio; float div(float a, float b) { return a / b; } void main() { auto c = 3.div(4); writeln(c); }
Sep 06 2016
prev sibling parent R <rjmcguire gmail.com> writes:
On Tuesday, 6 September 2016 at 15:00:48 UTC, Sai wrote:
 Thanks for the replies.

 I tend to use a lot of float math (robotics and automation) so 
 I almost always want float output in case of division. And once 
 in a while I bump into this issue.

 I am wondering what are the best ways to work around it.

     float c = a / b;     // a and b could be integers.

 Some solutions:

     float c = cast!float(a) / b;
     float c = 1f * a / b;


 Any less verbose ways to do it?

 Another solution I am thinking is to write a user defined 
 integer type with an overloaded division to return a float 
 instead and use it everywhere in place of integers. I am 
 curious how this will work out.
http://code.dlang.org/packages/fixed ?
Sep 07 2016
prev sibling parent pineapple <meapineapple gmail.com> writes:
On Tuesday, 6 September 2016 at 07:26:37 UTC, Andrea Fontana 
wrote:
 Integer division and modulo are not bugs.
Quoted for emphasis If you want floating point math, then declare your variables as floats.
Sep 07 2016
prev sibling parent reply Daniel Kozak via Digitalmars-d <digitalmars-d puremagic.com> writes:
Dne 6.9.2016 v 09:04 Sai via Digitalmars-d napsal(a):
 Consider this:

 import std.stdio;
 void main()
 {
     byte a = 6, b = 7;
     auto c = a + b;
     auto d = a / b;
     writefln("%s, %s", typeof(c).stringof, c);
     writefln("%s, %s", typeof(d).stringof, d);
 }

 Output :
 int, 13
 int, 0

 I really wish d gets promoted to a float. Besides C compatibility, any 
 reason why d got promoted only to int even at the risk of serious bugs 
 and loss of precision?

 I know I could have typed "auto a = 6.0" instead, but still it feels 
 like an half-baked promotion rules.
No, it is really important rule. If there will be automatic promotion to float for auto it will hurt performance in cases when you want int and it will break things. But maybe in below case it could make more sense: float d = a / b; // or it could print a warning because there is a high probability this is an error ok maybe something like linter could be use to find those places
Sep 06 2016
parent reply deadalnix <deadalnix gmail.com> writes:
On Tuesday, 6 September 2016 at 07:52:47 UTC, Daniel Kozak wrote:
 No, it is really important rule. If there will be automatic 
 promotion to float for auto it will hurt performance
 in cases when you want int and it will break things.
The performance have nothing to do with it. In fact float division is way faster than integer division, try it. It is all about correctness. Integer and floating point division have different semantic.
Sep 06 2016
parent reply Daniel Kozak via Digitalmars-d <digitalmars-d puremagic.com> writes:
Dne 6.9.2016 v 22:51 deadalnix via Digitalmars-d napsal(a):

 On Tuesday, 6 September 2016 at 07:52:47 UTC, Daniel Kozak wrote:
 No, it is really important rule. If there will be automatic promotion 
 to float for auto it will hurt performance
 in cases when you want int and it will break things.
The performance have nothing to do with it. In fact float division is way faster than integer division, try it. It is all about correctness. Integer and floating point division have different semantic.
You are right, on my pc speed is same, but I am remember that there has been some performance problems last time i checked (something about only one FPU on my bulldozer cpu)
Sep 06 2016
parent reply Sai <test test.com> writes:
I suspected the same, most of the CPUs support fast floating 
point operations anyway (with FPUs), shouldn't take a lot more 
time than doing integer arithmetic. Unless we are targeting 8bit 
avr or something similar.

And precision argument doesn't seem strong either, since, which 
is more precise 3/7 = 0 or 0.4285 ?

I am not suggesting we change the promotion rules now, most 
likely never going to happen. But I am trying to find a good 
rationale for the existing rules and unable to find a good one.





On Wednesday, 7 September 2016 at 05:31:08 UTC, Daniel Kozak 
wrote:
 Dne 6.9.2016 v 22:51 deadalnix via Digitalmars-d napsal(a):

 On Tuesday, 6 September 2016 at 07:52:47 UTC, Daniel Kozak 
 wrote:
 No, it is really important rule. If there will be automatic 
 promotion to float for auto it will hurt performance
 in cases when you want int and it will break things.
The performance have nothing to do with it. In fact float division is way faster than integer division, try it. It is all about correctness. Integer and floating point division have different semantic.
You are right, on my pc speed is same, but I am remember that there has been some performance problems last time i checked (something about only one FPU on my bulldozer cpu)
Sep 07 2016
next sibling parent reply Lodovico Giaretta <lodovico giaretart.net> writes:
On Wednesday, 7 September 2016 at 14:46:46 UTC, Sai wrote:
 I suspected the same, most of the CPUs support fast floating 
 point operations anyway (with FPUs), shouldn't take a lot more 
 time than doing integer arithmetic. Unless we are targeting 
 8bit avr or something similar.

 And precision argument doesn't seem strong either, since, which 
 is more precise 3/7 = 0 or 0.4285 ?

 I am not suggesting we change the promotion rules now, most 
 likely never going to happen. But I am trying to find a good 
 rationale for the existing rules and unable to find a good one.
x == x/k + x%k The above formula holds in integer arithmetic. It is fundamental in many operations. You cannot achieve the same with floating point calculations. Whenever you do batch jobs, dividing you work into groups (and you don't really want 2.3 groups) and whenever you iterate the digits of a number, implicit floating point conversions can really hurt. I think the current state of affairs is fairly good. Adding implicit conversions would make it worst. What would probably make it better (but can't be changed now) is having two distinct operators, one for integer division and one with implicit floating point conversions.
Sep 07 2016
next sibling parent Lodovico Giaretta <lodovico giaretart.net> writes:
On Wednesday, 7 September 2016 at 15:09:42 UTC, Lodovico Giaretta 
wrote:
 x == x/k + x%k
Of course that was: x == (x/k)*k + x%k But ok, you got the idea: going back and forth is lossless, just remember to add the modulus.
Sep 07 2016
prev sibling parent reply John Colvin <john.loughran.colvin gmail.com> writes:
On Wednesday, 7 September 2016 at 15:09:42 UTC, Lodovico Giaretta 
wrote:
 I think the current state of affairs is fairly good. Adding 
 implicit conversions would make it worst. What would probably 
 make it better (but can't be changed now) is having two 
 distinct operators, one for integer division and one with 
 implicit floating point conversions.
python3 uses / for floating point division and // for integer. I really like the distinction, although I would prefer if / was disallowed on integer operands entirely, i.e. 3/2.0 is ok but 3/2 is not, that would be an error and you'd have to do 3 // 2
Sep 07 2016
parent reply Nick Treleaven <nick geany.org> writes:
On Wednesday, 7 September 2016 at 15:15:03 UTC, John Colvin wrote:
 python3 uses / for floating point division and // for integer. 
 I really like the distinction, although I would prefer if / was 
 disallowed on integer operands entirely, i.e. 3/2.0 is ok but 
 3/2 is not, that would be an error and you'd have to do 3 // 2
Personally I agree. A more nuanced solution is filed here: https://issues.dlang.org/show_bug.cgi?id=12452 At the end of the description, Don is quoted:
 It is indeed a common floating-point bug.

 I came up with a solution for this a couple of years ago, never
 got around to doing a pull request, but it's on the newsgroup
 somewhere. It's a little extension to the range propagation
 implementation. You add a boolean flag to the range, which
 indicates 'a fractional part has been discarded'. This flag gets
 set whenever you perform an integer division (or integer
 exponentiation with a negative power), and is cleared whenever
 there is a cast or a bitwise operation.

 Then, disallow implicit casting from integer to floating point
 whenever the fractional bit is set. Catches all these kinds of
 bugs, doesn't require any changes to the language.
Sep 07 2016
parent Sai <test test.com> writes:
On Wednesday, 7 September 2016 at 16:04:05 UTC, Nick Treleaven 
wrote:
 On Wednesday, 7 September 2016 at 15:15:03 UTC, John Colvin 
 wrote:
 python3 uses / for floating point division and // for integer. 
 I really like the distinction, although I would prefer if / 
 was disallowed on integer operands entirely, i.e. 3/2.0 is ok 
 but 3/2 is not, that would be an error and you'd have to do 3 
 // 2
Personally I agree. A more nuanced solution is filed here: https://issues.dlang.org/show_bug.cgi?id=12452 At the end of the description, Don is quoted:
 It is indeed a common floating-point bug.
 ...
WOW, I didn't know python 3 fixed this issue, and I just found out that python 2 can also do it by importing from future. I have been using python 2.7 at my work for several years without knowing this and ran into this issue so many times, stupid me. Thanks for the info, I will update my python code asap. (In my defense, I am not a full time programmer). In D though, all solutions seem to add noise at the usage site, template solution with alias this might be the cleanest to retrofit all integers with floating point division. - Sai
Sep 07 2016
prev sibling parent deadalnix <deadalnix gmail.com> writes:
On Wednesday, 7 September 2016 at 14:46:46 UTC, Sai wrote:
 I suspected the same, most of the CPUs support fast floating 
 point operations anyway (with FPUs), shouldn't take a lot more 
 time than doing integer arithmetic. Unless we are targeting 
 8bit avr or something similar.
No. Floating point in binaries are represented as v = m * 2 ^ e Now: v0 / v1 = (m0 * 2 ^ e0) / (m1 * 2 ^ e1) v0 / v1 = (m0 / m1) * 2 ^ (e0 - e1) ie to do a 32 bits float division, you need to do a 24 bits integer division, while when doing a 32bits integer division you need to do a 32bits integer division (!) The same apply to floating point multiply that are usually faster than integer multiply. In fact, on some machines, multiplying floats is faster than adding them.
Sep 07 2016