• Post Reply Bookmark Topic Watch Topic
  • New Topic
programming forums Java Mobile Certification Databases Caching Books Engineering Micro Controllers OS Languages Paradigms IDEs Build Tools Frameworks Application Servers Open Source This Site Careers Other Pie Elite all forums
this forum made possible by our volunteer staff, including ...
Marshals:
  • Campbell Ritchie
  • Ron McLeod
  • Rob Spoor
  • Tim Cooke
  • Junilu Lacar
Sheriffs:
  • Henry Wong
  • Liutauras Vilda
  • Jeanne Boyarsky
Saloon Keepers:
  • Jesse Silverman
  • Tim Holloway
  • Stephan van Hulst
  • Tim Moores
  • Carey Brown
Bartenders:
  • Al Hobbs
  • Mikalai Zaikin
  • Piet Souris

How to detect and prevent integer overflow when multiplying an integer by float in Java?

 
Greenhorn
Posts: 24
jQuery MySQL Database PHP
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
I have read this article NUM00-J. Detect or prevent integer overflow and consulted a lot of questions on StackOverflow.
It can be easily seen that, there are many solutions to prevent integer overflow when multiplying an integer by an integer.
But I wonder is there any solution to prevent integer overflow when multiplying an integer by float?
My current (silly) solution:

But it has a lot of problems:
  • It can get the expected result when multiplying performs multiplication with both parameters having to be small numbers.
  • When either parameter is large digits the result is bound to be incorrect (I know in part because of the floating-point data type).
  • Suppose if the result of the calculation is even greater than the maximum value of double, it will be unstoppable and return a negative number.

  • Your answer will help me a lot.
    I would be very grateful for that!
     
    Saloon Keeper
    Posts: 8579
    71
    Eclipse IDE Firefox Browser MySQL Database VI Editor Java Windows
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator
    How about:
    Do you really want to return MAX_VALUE on overflow?
     
    Marshal
    Posts: 22450
    121
    Eclipse IDE Spring VI Editor Chrome Java Windows
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator
    How about Math.multiplyExact(a, b)? It throws an exception if there would be overflow.
     
    Tan Quang
    Greenhorn
    Posts: 24
    jQuery MySQL Database PHP
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator

    Carey Brown wrote:How about:
    Do you really want to return MAX_VALUE on overflow?


    Well, I want it to return the max value of int if the result overflows the max value of int. But why would you cast the value of a from int to double? And b here is a float, not an integer or a long!
     
    Tan Quang
    Greenhorn
    Posts: 24
    jQuery MySQL Database PHP
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator

    Rob Spoor wrote:How about Math.multiplyExact(a, b)? It throws an exception if there would be overflow.


    Did you read my question?
    I ask: Multiply an integer by float.
    I'm NOT asking: Multiply an integer by an integer.
    You can't cast float to int parameter unless you cast float to int, but if you cast float to int, the result will be incorrect, the error will be huge. (Example: You multiply 1000 by 2.5, the result will be 2500, but if you cast 2.5 to int you will only multiply by 2 because it will remove the decimal part, the result is 2000, the error is too big).
     
    Sheriff
    Posts: 8064
    569
    Mac OS X VI Editor BSD Linux
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator

    Tan Quang wrote:(Example: You multiply 1000 by 2.5, the result will be 2500, but if you cast 2.5 to int you will only multiply by 2 because it will remove the decimal part, the result is 2000, the error is too big)


    I'm a bit confused by this thread. So what is not too big error in your domain?
     
    Tan Quang
    Greenhorn
    Posts: 24
    jQuery MySQL Database PHP
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator

    Liutauras Vilda wrote:

    Tan Quang wrote:(Example: You multiply 1000 by 2.5, the result will be 2500, but if you cast 2.5 to int you will only multiply by 2 because it will remove the decimal part, the result is 2000, the error is too big)


    I'm a bit confused by this thread. So what is not too big error in your domain?


    What "domain" are you talking about here? If you talk about the "NUM00-J. Detect or prevent integer overflow" link I mentioned in the post, sorry, this is not my domain, this is SEI CERT article, it's currently featured article and examples for questions I've read on StackOverflow.
     
    Master Rancher
    Posts: 4028
    53
    • Likes 2
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator
    There are multiple issues here to discuss.

    First, I think several of us would recommend not returning Integer.MAX_VALUE, but rather throwing an exception, if the result is greater than Integer.MAX_VALUE.  Because that may be a huge error in the calculation, and it's usually better to handle that explicitly (e.g. in a catch block) than to just pass the incorrect "result" around as if nothing has happened.  But, if you really wat or need to return MAX_VALUE, you can I suppose - but it seems like bad design to me.

    Also, shouldn't you also check for c < Integer.MIN_VALUE as well?  That's also possible.

    I do agree that for cases where there is no overflow, it makes sense to return answers as accurate as possible, and for that, the Math.exactMultiply() methods are not really helpful since they do not allow float or double.  You want to be able to multiply something like 40 * 1.5 and get 60, not 40, I get that.

    Now, there's a small problem with this statement:

    The problem is that the "a * b" part is evaluated first to produce a float, and then it gets converted to a double.  So, you have the possibility of introducing additional roundoff error or overflow error when you don't have to.  That's the problem that Carey is solving with this:

    By converting to a double first, the multiplication is performed using doubles, and the result is less likely to be rounded or have overflow.


    Tan Quang wrote:It can get the expected result when multiplying performs multiplication with both parameters having to be small numbers.


    Can you give an example of this one?

    Tan Quang wrote:When either parameter is large digits the result is bound to be incorrect (I know in part because of the floating-point data type).


    Well, if that's a concern, why use float at all here, for starters?  You will get much more precision with double - why not use it?

    However, yes, it's still possible to get floating-point roundoff here.  If that's a concern, you should do the whole calculation using BigDecimal objects.  It will be slower, but it can be as precise as you need.  Note that you should probably not accept a float parameter in this case - it's already got some floating-point roundoff built into it. Better to accept a BigDecimal or a String that you convert to BigDecimal.

    Tan Quang wrote:Suppose if the result of the calculation is even greater than the maximum value of double, it will be unstoppable and return a negative number.


    Well, if you cast to (double) as discussed above, this problem goes away.  Integer.MAX_VALUE * Float.MAX_VALUE = 7.307507747690261E47 which is far less than Double.MAX_VALUE.  Although if you replace float with double as also discussed above, the problem returns.  So you should probably use  BigDecimal, also discussed above.
     
    Mike Simmons
    Master Rancher
    Posts: 4028
    53
    • Likes 2
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator
    One other point, we should be careful about converting a double to an int by casting.  Remember that this is effectively rounding down, for positive numbers... and that may not be what you want.  Consider, if the double version of the result is 5.9, do you want to return 5, or 6?  And, what if it's 5.9999?  What if it's -5.9 or -5.9999?  Decide what you think the best answer is for cases like this, and make sure your code returns the appropriate result.

    Personally, I would use Math.round() in most cases like this.  But maybe you need different results...
     
    Sheriff
    Posts: 26773
    82
    Eclipse IDE Firefox Browser MySQL Database
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator

    Tan Quang wrote:Did you read my question?
    I ask: Multiply an integer by float.
    I'm NOT asking: Multiply an integer by an integer.

    If you scroll down a bit you'll find an overloaded version with parameters (int, long). More suitable for your question?
     
    Tan Quang
    Greenhorn
    Posts: 24
    jQuery MySQL Database PHP
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator

    Mike Simmons wrote:There are multiple issues here to discuss.

    First, I think several of us would recommend not returning Integer.MAX_VALUE, but rather throwing an exception, if the result is greater than Integer.MAX_VALUE.  Because that may be a huge error in the calculation, and it's usually better to handle that explicitly (e.g. in a catch block) than to just pass the incorrect "result" around as if nothing has happened.  But, if you really wat or need to return MAX_VALUE, you can I suppose - but it seems like bad design to me.

    Also, shouldn't you also check for c < Integer.MIN_VALUE as well?  That's also possible.

    I do agree that for cases where there is no overflow, it makes sense to return answers as accurate as possible, and for that, the Math.exactMultiply() methods are not really helpful since they do not allow float or double.  You want to be able to multiply something like 40 * 1.5 and get 60, not 40, I get that.

    Now, there's a small problem with this statement:

    The problem is that the "a * b" part is evaluated first to produce a float, and then it gets converted to a double.  So, you have the possibility of introducing additional roundoff error or overflow error when you don't have to.  That's the problem that Carey is solving with this:

    By converting to a double first, the multiplication is performed using doubles, and the result is less likely to be rounded or have overflow.


    Tan Quang wrote:It can get the expected result when multiplying performs multiplication with both parameters having to be small numbers.


    Can you give an example of this one?

    Tan Quang wrote:When either parameter is large digits the result is bound to be incorrect (I know in part because of the floating-point data type).


    Well, if that's a concern, why use float at all here, for starters?  You will get much more precision with double - why not use it?

    However, yes, it's still possible to get floating-point roundoff here.  If that's a concern, you should do the whole calculation using BigDecimal objects.  It will be slower, but it can be as precise as you need.  Note that you should probably not accept a float parameter in this case - it's already got some floating-point roundoff built into it. Better to accept a BigDecimal or a String that you convert to BigDecimal.

    Tan Quang wrote:Suppose if the result of the calculation is even greater than the maximum value of double, it will be unstoppable and return a negative number.


    Well, if you cast to (double) as discussed above, this problem goes away.  Integer.MAX_VALUE * Float.MAX_VALUE = 7.307507747690261E47 which is far less than Double.MAX_VALUE.  Although if you replace float with double as also discussed above, the problem returns.  So you should probably use  BigDecimal, also discussed above.


    Tan Quang wrote:It can get the expected result when multiplying performs multiplication with both parameters having to be small numbers.


    For example, when multiplying a few hundred thousand to several million by a small float, the result can still be accurate without error.
    I also researched on double, it will help b no more error (since it doesn't convert 1.8 to 1.79999...) but since double uses 8 bytes, twice as much as float. So in some cases, I fear the calculation will take a long time.
    Why am I asking to return Integer.MAX_VALUE? For example in a game, if the damage dealt by the player is below 0, that equates to the target receiving the damage being restored for an amount of HP equal to the damage inflicted by the player instead of being deducted. This is pretty silly, isn't it?
    Using BigDecimal seems to be a perfect solution when doing calculations that need very high precision but it will also take more time. Therefore, I dismissed the idea of using BigDecimal for this case. I need something with relatively high precision, stable and fast for this case, but since the data type of the calculation result is int and not float or double, the result is error in the range less than 1 (0 - 0.9999...) is no problem!
    I'm still thinking about casting a to double, because as far as I know int data type is not lossy like float, so I think just converting b from float to double is enough.
     
    Tan Quang
    Greenhorn
    Posts: 24
    jQuery MySQL Database PHP
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator

    Paul Clapham wrote:

    Tan Quang wrote:Did you read my question?
    I ask: Multiply an integer by float.
    I'm NOT asking: Multiply an integer by an integer.

    If you scroll down a bit you'll find an overloaded version with parameters (int, long). More suitable for your question?


    I explained why it is NOT possible to use any int or long data types for the rest of the parameters above. I don't want something from 2.5 to be 2, huge error, very bad idea!
     
    Tan Quang
    Greenhorn
    Posts: 24
    jQuery MySQL Database PHP
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator

    Mike Simmons wrote:One other point, we should be careful about converting a double to an int by casting.  Remember that this is effectively rounding down, for positive numbers... and that may not be what you want.  Consider, if the double version of the result is 5.9, do you want to return 5, or 6?  And, what if it's 5.9999?  What if it's -5.9 or -5.9999?  Decide what you think the best answer is for cases like this, and make sure your code returns the appropriate result.

    Personally, I would use Math.round() in most cases like this.  But maybe you need different results...


    I have no idea how many digits the b parameter has after the decimal point. What I'm interested in is a fast, accurate result with as little error as possible.
     
    Saloon Keeper
    Posts: 1283
    40
    Eclipse IDE Postgres Database C++ Java
    • Likes 1
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator

    I also researched on double, it will help b no more error (since it doesn't convert 1.8 to 1.79999...) but since double uses 8 bytes, twice as much as float. So in some cases, I fear the calculation will take a long time.



    To my knowledge, virtually all all hardware that supports Java SE does both long and double maths in hardware, which can even be faster than float or int.

    I had memorized years ago that "You should just forget about float, it won't be any faster than double."

    When I started working in AI for a while, that advice went out the window, but because we a) often didn't need the extra precision anyway and b) had mind-bogglingly enormous data sets.

    The reason float was often preferred to double was to save space for the data, not time per se.

    On CPU's there is no sense in using float16 instead of float32 or float64 (not Java types) because most CPU's do not have special float16 instructions, so the time to convert back and forth is prohibitive and mostly just isn't done.

    What I didn't realize is that the GPU's that people tend to use nowadays for Serious Number Crunching support float16 natively, so that if you have absolutely tremendous data sets, and cache misses are a big part of what is slowing you down, they will happily use float16 when precision isn't needed.

    Is doing "normal Java maths" on Java long and double types actually slower than using int and float?

    I didn't think so and was thinking you would only do that because you needed neither the extended range nor precision and wanted to save space, but I will watch this thread for a reply by someone who knows for sure, or has recently measured.
     
    Mike Simmons
    Master Rancher
    Posts: 4028
    53
    • Likes 1
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator
    The only reason I would use float is if I'm dealing with large arrays of numbers.  Much like Jesse wrote above.  In those cases you may indeed benefit from reduced storage space compared to double.  (In tradeoff with precision, of course.). Even then, most of the actual calculations might as well be done with doubles.  Even if you're storing results back in float arrays.

    You may well disagree, and that's fine.  But, you would be well advised to test the performance of your code to see if it really makes any difference.  Chances are very good that it won't.  And, given your concerns about accuracy, using double rather than float seems a really good idea.

    Given your performance concerns about something as minor as using double rather than float, I expect you really won't want to use BigDecimal, unless there's no other way to get the precision you need.  OK.

    I would also question why you would want to convert the result back to an int, given that it can introduce additional errors.  If you were using long rather than int, it might make more sense... long can have more precision than double, but with a reduced range.  Except that given that the multiplication needs to be done with double (assuming BigDecimal is not involved), that extra precision in long isn't really accessible.  Your result will still have the effective precision of double, with added roundoff errors as you convert it to an integer value.  Not sure what the point of that would be...

    But if you really need the result to be an int, and can't afford the slowness of BigDecimal, here is what I would use:

    It might be worthwhile to create an OverflowException which extends ArithmeticException, to make it easier to catch that specific exception if you need to.
     
    Mike Simmons
    Master Rancher
    Posts: 4028
    53
    • Likes 1
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator

    Tan Quang wrote:I have no idea how many digits the b parameter has after the decimal point. What I'm interested in is a fast, accurate result with as little error as possible.


    Well, to minimize the error you should use round().  That way 5.9 becomes 6 (error of 0.1) rather than 5 (error of 0.9).
     
    Tan Quang
    Greenhorn
    Posts: 24
    jQuery MySQL Database PHP
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator

    Jesse Silverman wrote:

    I also researched on double, it will help b no more error (since it doesn't convert 1.8 to 1.79999...) but since double uses 8 bytes, twice as much as float. So in some cases, I fear the calculation will take a long time.



    To my knowledge, virtually all all hardware that supports Java SE does both long and double maths in hardware, which can even be faster than float or int.

    I had memorized years ago that "You should just forget about float, it won't be any faster than double."

    When I started working in AI for a while, that advice went out the window, but because we a) often didn't need the extra precision anyway and b) had mind-bogglingly enormous data sets.

    The reason float was often preferred to double was to save space for the data, not time per se.

    On CPU's there is no sense in using float16 instead of float32 or float64 (not Java types) because most CPU's do not have special float16 instructions, so the time to convert back and forth is prohibitive and mostly just isn't done.

    What I didn't realize is that the GPU's that people tend to use nowadays for Serious Number Crunching support float16 natively, so that if you have absolutely tremendous data sets, and cache misses are a big part of what is slowing you down, they will happily use float16 when precision isn't needed.

    Is doing "normal Java maths" on Java long and double types actually slower than using int and float?

    I didn't think so and was thinking you would only do that because you needed neither the extended range nor precision and wanted to save space, but I will watch this thread for a reply by someone who knows for sure, or has recently measured.


    I did something like this:

    Result:

    memory: 27792 time: 0.15 exit code: 0


    Then I try to convert it to double:

    Result:

    memory: 28596 time: 0.17 exit code: 0


    It seems that if using double, memory and time will be higher than float even though they have the same result of calculation.
    I tested them on OnlineGDB. Can you optimize the calculation?
     
    Mike Simmons
    Master Rancher
    Posts: 4028
    53
    • Likes 1
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator
    Well, those numbers look very close to me, and the time seems too short to mean much... Java performance times vary substantially in different circumstances, and you generally need to repeat the operation many times to have a meaningful result.  And if you're doing IO with a method like System.out.println(), that will be far slower than the calculation.  So I don't think those numbers are very meaningful.  Try doing millions of calculations, with no IO, to get a better idea of the performance.

    Moreover, you seem to think it's very important to be as accurate as possible, and also to be as fast as possible.  The thing is, those two things can be in conflict, to some extent.  And you haven't really given any clear idea of which one is more important.  As an example, I pointed out the difference between casting to int, and using the round() method to reduce roundoff error.  Well, calling the round method may be a little slower than simply casting to int - is it worth it?  Personally I think it is, but that's really your decision; we don't know what you're planning to use this method for.  You need to decide how much error is acceptable to you.

    Generally, it would be best to first, make sure your code is as accurate as possible, ignoring the performance.  Then make sure you have a good set of unit tests to verify that your code is achieving the necessary accuracy.  Then write a performance test that gives you a good measure of how fast it is.  Only after you have those, then try changing the code to make it faster.  Otherwise you don't know when your changes are introducing unacceptable problems with accuracy.
     
    Tan Quang
    Greenhorn
    Posts: 24
    jQuery MySQL Database PHP
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator

    Mike Simmons wrote:The only reason I would use float is if I'm dealing with large arrays of numbers.  Much like Jesse wrote above.  In those cases you may indeed benefit from reduced storage space compared to double.  (In tradeoff with precision, of course.). Even then, most of the actual calculations might as well be done with doubles.  Even if you're storing results back in float arrays.

    You may well disagree, and that's fine.  But, you would be well advised to test the performance of your code to see if it really makes any difference.  Chances are very good that it won't.  And, given your concerns about accuracy, using double rather than float seems a really good idea.

    Given your performance concerns about something as minor as using double rather than float, I expect you really won't want to use BigDecimal, unless there's no other way to get the precision you need.  OK.

    I would also question why you would want to convert the result back to an int, given that it can introduce additional errors.  If you were using long rather than int, it might make more sense... long can have more precision than double, but with a reduced range.  Except that given that the multiplication needs to be done with double (assuming BigDecimal is not involved), that extra precision in long isn't really accessible.  Your result will still have the effective precision of double, with added roundoff errors as you convert it to an integer value.  Not sure what the point of that would be...

    But if you really need the result to be an int, and can't afford the slowness of BigDecimal, here is what I would use:

    It might be worthwhile to create an OverflowException which extends ArithmeticException, to make it easier to catch that specific exception if you need to.


    Yes, the solution you gave, change b to double looks fine, the result will be more correct. But I don't think it's necessary to call Math.round on return because casting int to double is the same as casting int to float, it simply removes the decimal part, so the error won't be too big (maximum error is 1). I'm a little concerned about calling Math.round because it can affect performance and speed.
     
    Tan Quang
    Greenhorn
    Posts: 24
    jQuery MySQL Database PHP
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator

    Mike Simmons wrote:Well, those numbers look very close to me, and the time seems too short to mean much... Java performance times vary substantially in different circumstances, and you generally need to repeat the operation many times to have a meaningful result.  And if you're doing IO with a method like System.out.println(), that will be far slower than the calculation.  So I don't think those numbers are very meaningful.  Try doing millions of calculations, with no IO, to get a better idea of the performance.

    Moreover, you seem to think it's very important to be as accurate as possible, and also to be as fast as possible.  The thing is, those two things can be in conflict, to some extent.  And you haven't really given any clear idea of which one is more important.  As an example, I pointed out the difference between casting to int, and using the round() method to reduce roundoff error.  Well, calling the round method may be a little slower than simply casting to int - is it worth it?  Personally I think it is, but that's really your decision; we don't know what you're planning to use this method for.  You need to decide how much error is acceptable to you.

    Generally, it would be best to first, make sure your code is as accurate as possible, ignoring the performance.  Then make sure you have a good set of unit tests to verify that your code is achieving the necessary accuracy.  Then write a performance test that gives you a good measure of how fast it is.  Only after you have those, then try changing the code to make it faster.  Otherwise you don't know when your changes are introducing unacceptable problems with accuracy.


    Well, with those snippets I test about 10 times each. Ignoring the similarity of memory, the timing of code that uses floats typically fluctuates between 0.08 and 0.15, while doubles are a bit higher, up to 0.1 to 0.3.
    But I think, nothing is perfect, I will use int for a and double for b, memory sacrifice is not so important anymore, just speed and accuracy.
     
    Marshal
    Posts: 74020
    332
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator

    Tan Quang wrote:. . .  memory sacrifice is not so important anymore, just speed and accuracy.

    Memory? I can buy enough memory to store 10⁹ doubles for slightly more than the price of two large pizzas.
    Speed and accuracy? You get accuracy, but not precision, with doiubles; if you want precision, you will have to use BigDecimal, as somebody suggested earlier.Use the valueOf() method, not the constructor taking a double to calculate x. Find out about the BigDecimal.intValue() method.
     
    Jesse Silverman
    Saloon Keeper
    Posts: 1283
    40
    Eclipse IDE Postgres Database C++ Java
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator
    This contains the trigger-warning-word should in the title, and could spark contention because there are plenty of people being paid as Java developers that don't know everything in this video.

    However, anyone who started or posted on this thread should know the stuff in this recent excellent talk that tells "more than you probably knew or wanted to about floating point math in Java":

    https://www.youtube.com/watch?v=ajaHQ9S4uTA

    Interestingly, Java does such a good job of implementation that I would say that ANYBODY using floating point math should know that material, even if they rarely use Java.

    At 6:29 we see that float gives you "6 to 9 decimal digits of precision" which alone would make me rule out using it in the way the OP seems to want here, despite the fact that I have worked on projects in the past year where they were very happy to make the trade-off between storage space and precision.  It felt weird to me, but then again, we were in Python, so EVERYTHING felt a bit weird to me.

    For those REALLY interested in the workings of floats and doubles and operations on them, the above was apparently a boiled-down version of a longer talk by the same Java expert, seen here:
    https://www.youtube.com/watch?v=fQ_EtTJHKsM

    I haven't watched all that one, despite the fact that I probably should at some point.
    I have worked on many projects that used floating point, and felt satisfied that I knew a bit more than most of the other developers.
    Both videos show that there are some tricky, counter-intuitive behaviors that will not be expected just from treating float and double as black boxes that somehow magically represent real numbers.
    Once you understand how they work, these weird things make perfect sense, even if you later forget some of the details that hide inside.


     
    Jesse Silverman
    Saloon Keeper
    Posts: 1283
    40
    Eclipse IDE Postgres Database C++ Java
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator
    For those interested, but not interested enough to watch Joe's videos, the reason I was looking to eliminate any solutions involving float out of the gate is shown here:
    jshell> int i = Integer.MAX_VALUE - 5;
    i ==> 2147483642

    jshell> int i2 = Integer.MAX_VALUE - 6;
    i2 ==> 2147483641

    jshell> int i3 = Integer.MAX_VALUE - 7;
    i3 ==> 2147483640

    jshell> i
    i ==> 2147483642

    jshell> i2
    i2 ==> 2147483641

    jshell> i3
    i3 ==> 2147483640

    jshell> float f = (float)i
    f ==> 2.14748365E9

    jshell> float f2 = (float)i2
    f2 ==> 2.14748365E9

    jshell> float f3 = (float)i3
    f3 ==> 2.14748365E9

    jshell> (int)(f3 - f)
    $17 ==> 0
     
    Jesse Silverman
    Saloon Keeper
    Posts: 1283
    40
    Eclipse IDE Postgres Database C++ Java
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator
    People doing serious number crunching today are generally doing it on GPU's, which have very different performance characteristics than CPU's.

    There is more than one kind of memory involved, and moving stuff back and forth is probably more expensive than doing the computations themselves, it reminds me of the light studying of SuperComputing math I did back in Engineering School.

    So if you are watching NVIDIA presentations, all kinds of decisions go differently.  For instance, a lot of them don't seem to need precision, float32 is very popular and float16 is used when it is good enough (the very notion of float16 seemed like a joke to me, but it has its use cases and on GPU hardware you do get performance benefits if it is good enough)...

    The videos I linked to and all my comments not talking about GPU math apply to all modern CPU-based calculations that don't delegate to the GPU.

    BigDecimal is pretty interesting to me too, but is on the other end of the spectrum from the GPU-based stuff (valuing precision above performance).

    I still think of the double type and operations on it to be "normal floating point math" as important as BigDecimal and GPU stuff are in the domains that need those characteristics.

    For Campbell:
    The authors of the site that the OP was coming from have a similar Reading List to you, I note in particular in the References:
    [Bloch 2001] Joshua Bloch, Effective Java: Programming Language Guide, Addison-Wesley Professional, Boston, 2001.


    [Bloch 2005a] Joshua Bloch and Neal Gafter, Java™ Puzzlers: Traps, Pitfalls, and Corner Cases, Addison-Wesley Professional, Boston, 2005.


    [Bloch 2005b] Joshua Bloch and Neal Gafter, Yet More Programming Puzzlers, JavaOne Conference, 2005.


    [Bloch 2007] Joshua Bloch, Effective Java™ Reloaded: This Time It's (Not) for Real, JavaOne Conference, 2007.


    [Bloch 2008] Joshua Bloch, Effective Java™: Programming Language Guide, 2nd ed., Addison-Wesley Professional, Boston, 2008.


    [Bloch 2009] Joshua Bloch and Neal Gafter, Return of the Puzzlers: Schlock and Awe, JavaOne Conference, 2009.

     
    Campbell Ritchie
    Marshal
    Posts: 74020
    332
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator
    Can I have some more details of those Bloch and Gafter links please. I have only read Java Puzzlers.
     
    Jesse Silverman
    Saloon Keeper
    Posts: 1283
    40
    Eclipse IDE Postgres Database C++ Java
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator
    I couldn't find those exact ones in a cursory search either.

    For those who Just Can't Get Enough Joshua Bloch,  and he does seem to be the absolute King of "Avoiding Java Gotchas in Code That Must Work Correctly", to be fair, I did find these while looking.

    Campbell and those who feel the same way will probably want to watch all of them, and maybe re-watch at least parts of ones they haven't seen in a long time:

    https://www.youtube.com/watch?v=yGFok5AJAyc

    https://www.youtube.com/watch?v=qRTIpyd_snc

    https://www.youtube.com/watch?v=7qXfoZIqi2Q

    I am reminded of the huge difference between kinda sorta knowing a topic, pretty much, and REALLY knowing it very well...
     
    Campbell Ritchie
    Marshal
    Posts: 74020
    332
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator
    Thank you.
    I got the first one right in the first video. Only yet watched the first half.
     
    Tan Quang
    Greenhorn
    Posts: 24
    jQuery MySQL Database PHP
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator
    There's a lot to talk about here, but one thing is for sure, I'm not going to use BigDecimal (at least for now). BigDecimal has high accuracy but the cost is speed and memory, but I can sacrifice memory, but the result I need has relative precision and the computation speed should be fast and stable fixed (because it will be frequently used and calculated continuously). As for using double or float, I think I'lll use double because at least its precision will be higher than float.
    Here is my current solution:

    Although I still don't understand why cast a from int to double in the c operation, since a's data type is int, if somehow we make a larger than Integer.MAX_VAULE then casting a to double also can't fix the fact that a can't fail to become negative.
     
    Jesse Silverman
    Saloon Keeper
    Posts: 1283
    40
    Eclipse IDE Postgres Database C++ Java
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator
    The line that implements the check-for-max condition in line two is so long that it is effectively unreadable, so I'm not sure if it is right...



    I'd need to study it some more and question whether there isn't an easier-to-read/easier-to-check phrasing of the same check that wouldn't work just as fast or undetectably slower...

    You may not be planning to call these in the way I am seeing they could be called and return meaningless results, but looking at both of these:



    If a is Integer.MAX_VALUE and -1.0 < b < 1.0 you are returning Integer.MAX_VALUE instead of a well-defined, meaningful and computable finite result, including the case where b == 0.0 (!)
    Is that what you actually intend to do??
     
    Campbell Ritchie
    Marshal
    Posts: 74020
    332
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator
    Line 2 looks far too complicated to be correct.
    You don't need those three overloaded methods; you can use the method with two double parameters and the ints will be cast to doubles. That assumes you don't have any other overloaded versions of that method.
     
    Campbell Ritchie
    Marshal
    Posts: 74020
    332
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator

    Jesse Silverman wrote:. . . I'm not sure if it is right... . . .

    I am.
    It isn't.
     
    Jesse Silverman
    Saloon Keeper
    Posts: 1283
    40
    Eclipse IDE Postgres Database C++ Java
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator
    Hi Tan Quang:

    So we aren't "fighting straw men" here, can you state for what domain of values you expect the solution to work for?  i.e. which values of a and b?

    I am nearly sure that you don't want to return a result of Integer.MAX_VALUE for

    mulInt(Integer.MAX_VALUE, 0.0000)

    but have lost track of what values for a and b you are trying to return a "best product possible without overflow" for.

    Going back to what Mike said, it seems that returning a value of Integer.MAX_VALUE for any of these is missing the spirit of the page you linked to.

    There is currently no way for your solution to signal the difference in state of affairs between a HUGE OVERFLOW, likely to cause the reactor to melt down, the plane to crash or the patient to die, and a result that just happens to evaluate to Integer.MAX_VALUE

    The topic is endlessly fascinating, but I am not sure which use cases the solution you are moving towards is the best approach for.
     
    Campbell Ritchie
    Marshal
    Posts: 74020
    332
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator
    If the correct value is 2147483647 (=MAX_VALUE), the tiniest integer overflow error will produce a wildly incorrect answer and the company will crash, the stock market melt down, or the patient won't get into hospital at all.
     
    Tan Quang
    Greenhorn
    Posts: 24
    jQuery MySQL Database PHP
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator

    Jesse Silverman wrote:The line that implements the check-for-max condition in line two is so long that it is effectively unreadable, so I'm not sure if it is right...

    <br /> <br /> I'd need to study it some more and question whether there isn't an easier-to-read/easier-to-check phrasing of the same check that wouldn't work just as fast or undetectably slower... <br /> <br /> You may not be planning to call these in the way I am seeing they could be called and return meaningless results, but looking at both of these: <br /> <br />

    If a is Integer.MAX_VALUE and -1.0 < b < 1.0 you are returning Integer.MAX_VALUE instead of a well-defined, meaningful and computable finite result, including the case where b == 0.0 (!)
    Is that what you actually intend to do??


    That long piece of code is taken here: NUM00-J. Detect or prevent integer overflow
    I use these codes in the game I'm writing. What I want here is to prevent players from having to make silly mistakes when they have something too high (damage, currency,...) that has the ability to turn the largest number into a negative number. As in the example above, I don't want them to damage monsters to restore health points to monsters, or from a billionaire to suddenly become billions in debt.

    The main purpose is to prevent possible overflow.


    As for your problem, it is very practical, but I at least check that b must be greater than 0 to perform the calculation (because most of b are modules usually > 0 , there are only a few exceptions). As for currency, it's always 0 <= money <= Integer.MAX_VALUE (partially because I use the data type int unsigned and I also don't want the player's money to be negative, I don't want to when player purchase of goods will be added money instead of minus money).
    I also currently think that checking a is equal to Integer.MAX_VALUE here seems really unnecessary, I think it should be checked before doing the calculation.
     
    Tan Quang
    Greenhorn
    Posts: 24
    jQuery MySQL Database PHP
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator

    Jesse Silverman wrote:Hi Tan Quang:

    So we aren't "fighting straw men" here, can you state for what domain of values you expect the solution to work for?  i.e. which values of a and b?

    I am nearly sure that you don't want to return a result of Integer.MAX_VALUE for

    mulInt(Integer.MAX_VALUE, 0.0000)

    but have lost track of what values for a and b you are trying to return a "best product possible without overflow" for.

    Going back to what Mike said, it seems that returning a value of Integer.MAX_VALUE for any of these is missing the spirit of the page you linked to.

    There is currently no way for your solution to signal the difference in state of affairs between a HUGE OVERFLOW, likely to cause the reactor to melt down, the plane to crash or the patient to die, and a result that just happens to evaluate to Integer.MAX_VALUE

    The topic is endlessly fascinating, but I am not sure which use cases the solution you are moving towards is the best approach for.


    As I explained above, I always and only do the calculation if b is greater than 0. As for checking a equals Integer.MAX_VALUE which has also recently arisen, I simply don't want the player to have an integer overflow, from Integer.MAX_VALUE to something heavily indebted substance, and if a is really equal to Integer.MAX_VALUE, I think no need to do the math anymore, directly return the value of Integer.MAX_VALUE, so integer overflow a can be avoided.
     
    Jesse Silverman
    Saloon Keeper
    Posts: 1283
    40
    Eclipse IDE Postgres Database C++ Java
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator

    Tan Quang wrote:
    ...
    As for your problem, it is very practical, but I at least check that b must be greater than 0 to perform the calculation (because most of b are modules usually > 0 , there are only a few exceptions). As for currency, it's always 0 <= money <= Integer.MAX_VALUE (partially because I use the data type int unsigned and I also don't want the player's money to be negative, I don't want to when player purchase of goods will be added money instead of minus money).
    I also currently think that checking a is equal to Integer.MAX_VALUE here seems really unnecessary, I think it should be checked before doing the calculation.



    I am going to guess that your primary implementation language is NOT Java, given the highlighted data type above?

    People were offering various Java-specific solutions to your issue, probably based on the forum title they found the question in...

    I will agree that it is generally good that programmers are learning to or forcing themselves to think more about arithmetic overflow.
    When controlled and expected it can be fine, but the same casual approach can maim, kill or cost billions of dollars when it pops up someplace that matters enough...
     
    Tan Quang
    Greenhorn
    Posts: 24
    jQuery MySQL Database PHP
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator

    Jesse Silverman wrote:

    Tan Quang wrote:
    ...
    As for your problem, it is very practical, but I at least check that b must be greater than 0 to perform the calculation (because most of b are modules usually > 0 , there are only a few exceptions). As for currency, it's always 0 <= money <= Integer.MAX_VALUE (partially because I use the data type int unsigned and I also don't want the player's money to be negative, I don't want to when player purchase of goods will be added money instead of minus money).
    I also currently think that checking a is equal to Integer.MAX_VALUE here seems really unnecessary, I think it should be checked before doing the calculation.



    I am going to guess that your primary implementation language is NOT Java, given the highlighted data type above?

    People were offering various Java-specific solutions to your issue, probably based on the forum title they found the question in...

    I will agree that it is generally good that programmers are learning to or forcing themselves to think more about arithmetic overflow.
    When controlled and expected it can be fine, but the same casual approach can maim, kill or cost billions of dollars when it pops up someplace that matters enough...


    unsigned is a data type for storing data on MySQL. It's not a bad idea to avoid negative data (since its data range is from 0 to twice the maximum value of signed data type). But since java doesn't have an unsigned data type, something must be done to avoid overflow.
     
    Campbell Ritchie
    Marshal
    Posts: 74020
    332
    • Likes 1
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator

    Tan Quang wrote:. . . unsigned is a data type . . . on MySQL. . . . since java doesn't have an unsigned data type, something must be done to avoid overflow.

    Most languages support unsigned integer types. It is often possible to interconvert signed and unsigned numbers, which can cause overflow errors.
    I think you want to convert them to some datatype that supports the full range, maybe even BigInteger.
     
    Tan Quang
    Greenhorn
    Posts: 24
    jQuery MySQL Database PHP
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator

    Campbell Ritchie wrote:

    Tan Quang wrote:. . . unsigned is a data type . . . on MySQL. . . . since java doesn't have an unsigned data type, something must be done to avoid overflow.

    Most languages support unsigned integer types. It is often possible to interconvert signed and unsigned numbers, which can cause overflow errors.
    I think you want to convert them to some datatype that supports the full range, maybe even BigInteger.


    Unfortunately java doesn't support unsigned data type. Most solutions to have unsigned data type in java are to use data type with larger range of values. Example: I want an unsigned int data type (greater than Integer.MAX_VALUE), I need to use long to get that. But suppose I want a long unsigned data type (the MySQL equivalent of bigint unsigned)? Not to mention that java is very strict in setting the data type for variables, if indeed java supports unsigned data types like other programming languages, that would be great!
     
    Jesse Silverman
    Saloon Keeper
    Posts: 1283
    40
    Eclipse IDE Postgres Database C++ Java
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator
    Java still does not allow you to declare the type of a primitive as unsigned, nor are there UnsignedInteger and associated other wrapper types defined.

    There are a great number of methods (far too many to list here, in fact), in both the Integer and Long classes that have been added somewhat recently, mostly in Java 8 and 9 that make working with unsigned values much easier, please refer:

    https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/Integer.html

    https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/Long.html

    So you can't declare a Data Type to be unsigned, but for operations, you sure can specify to treat the operands and results as unsigned.

    I spent 11+ years working on a giant multi-lingual product (really more of a platform, actually) that had the same values represented in C/C++, SQL, C# and Java.

    There was more than a little pain around this (okay, sometimes a LOT) and these methods that are now part of the standard wrapper classes could probably have helped us some.

    The lack of there being a way to actually declare a Java VALUE unsigned still would cause us a lot of headaches even today, and I think we would still try to avoid exposing unsigned types to user api's.  Sadly, because we were working with many native and .Net api's, that was not always possible.  Hilarity sometimes ensued.

    I will add that actually needing the full RANGE of unsigned long is spectacularly uncommon.  I feel like 100% of the use cases I would be using the methods found in the provided links would be for compatibility with non-Java API's, but I may be forgetting something.

    When working in Pure Java (a luxury I rarely have had) I would generally avoid unsigned types wherever possible, it is not a good state of affairs to be having values that need to be reminded that they are indeed unsigned every time one operates on or compares them.


     
    With a little knowledge, a cast iron skillet is non-stick and lasts a lifetime.
    reply
      Bookmark Topic Watch Topic
    • New Topic