another (different) rounding problem

Questions and answers on designing your Servoy solutions, database modelling and other 'how do I do this' that don't fit in any of the other categories

Re: another (different) rounding problem

Postby lwjwillemsen » Thu Sep 21, 2017 2:00 pm

Mathematical rounding should always be correct in my opinion


That's the book all about:

A computer can not do true mathematical rounding due to the representation of numbers in a series of bits / bytes.
Lambert Willemsen
Vision Development BV
lwjwillemsen
 
Posts: 603
Joined: Sat Mar 14, 2009 5:39 pm
Location: The Netherlands

Re: another (different) rounding problem

Postby jcompagner » Thu Sep 21, 2017 2:46 pm

lwjwillemsen wrote:
Mathematical rounding should always be correct in my opinion


That's the book all about:

A computer can not do true mathematical rounding due to the representation of numbers in a series of bits / bytes.


exactly

i was already really confused about that statement..
Because there is no such thing a "Mathematical rounding" if you work with floating points notation numbers!!
you shouldn't really round
you only round because of " financial administration challenges."

if you calculate stuff like summing/dividing/multiply you name it, you should never round there, only the end result if " financial administration" requires that.

This should be really clear to everybody here, that rounding in javascript is NOT possible, you never are guaranteed that you get exactly that number (with 2 decimals)

looking at harjo's number:
4.725

if you round that in the few ways that are represented here then you get
4.72 righ? that is because it is very likely 4.724999999 (because 4.725 can be expressed exactly like that) where you start with or that 4.73 can't be exactly be shown like that and you really get 4.729999999999
thats why that +0.000001 works
but still you dont really have 4.73 ... what you really have is 4.73000001

That you then store that in a database of NUMERIC(10,2) that will delete the 00001 from it, but when you read it back it it can be that Servoy really reads it as BigDecimals (a real Numeric represenation class)
but at the moment you touch it in js it will be a floating point again and it will have something after it..
Johan Compagner
Servoy
User avatar
jcompagner
 
Posts: 8116
Joined: Tue May 27, 2003 7:26 pm
Location: The Internet

Re: another (different) rounding problem

Postby omar » Thu Sep 21, 2017 3:19 pm

I decided to do some rigorous tests on the different rounding methods above to get to the bottom of this and literally found thousands of rounding errors.

For example Marcs routine fails when rounding 1/201 (equals 0.004975124378109453) to 2 decimals returning 0.01 instead of 0.00. Another: 0.146 with precision 1 rounds to 0.2 etc.

Roberts routine fails when rounding 1/6667 (equals 0.000149992500037498125) to 4 decimals returning 0.0002 instead of 0.0001. Another: 0.206 with precision 8 returns 0.20600001 etc.

I tested using two methods: 1/x (1 divided by x) and composing decimal numbers by string concatenation. Let me know if you would like me to post the code for that.

The only rounding method that I have not found any errors in is the one I posted earlier. I guess nobody tested it because they figured it was to short to be able to work correctly ;-)

So until a better method comes along the best way is: (credit for the core of this solution goes to Jack Moore. See: http://www.jacklmoore.com/notes/rounding-in-javascript/)

Code: Select all
/**
* Round using exponential notation shifting
*
* @param {Number} value
* @param {Number} precision
*/
function round(value, precision) {
   return Number(Math.round(Number(Math.abs(value)+'e'+precision))+'e-'+precision) * (value < 0 ? -1 : 1)
}
Intrasoft, Founder
Omar van Galen
[email protected]
+31-(0)6-21234586
Servoy Developer
omar
 
Posts: 325
Joined: Sat Feb 12, 2011 4:51 pm
Location: Intrasoft, The Netherlands

Re: another (different) rounding problem

Postby ROCLASI » Thu Sep 21, 2017 4:58 pm

Nice!
I missed that one.
Robert Ivens
ROCLASI Software Solutions / JBS Group, Partner
SAN Developer / Servoy Valued Professional / Servoy Certified Developer
Twitter: @roclasi / @servoyforge
--
ServoyForge - Building Open Source Software.
PostgreSQL - The world's most advanced open source database.
User avatar
ROCLASI
Servoy Expert
 
Posts: 5285
Joined: Thu Oct 02, 2003 9:49 am
Location: Netherlands/Belgium

Re: another (different) rounding problem

Postby jcompagner » Fri Sep 22, 2017 9:37 am

omar wrote:
Code: Select all
/**
* Round using exponential notation shifting
*
* @param {Number} value
* @param {Number} precision
*/
function round(value, precision) {
   return Number(Math.round(Number(Math.abs(value)+'e'+precision))+'e-'+precision) * (value < 0 ? -1 : 1)
}



interesting that that works, it is for sure a bit slower as all the others ;)
because its quite a lot number -> to string (concat) -> number -> to string -> tonumber

So the magic here has to be in the Number constructor and the parse of the string that that constructor gets, that weird rounding errors won't happen..
Johan Compagner
Servoy
User avatar
jcompagner
 
Posts: 8116
Joined: Tue May 27, 2003 7:26 pm
Location: The Internet

Re: another (different) rounding problem

Postby omar » Fri Sep 22, 2017 9:47 am

If you leave out the second Number constructor it works as well but you will get an implicit conversion anyway. I included it myself to get rid of the Servoy warning that otherwise occurs. I like to keep my solutions completely free of warnings ;-) Performance is not that bad either, during testing I did several hundred millions of round operations in a few seconds.
Intrasoft, Founder
Omar van Galen
[email protected]
+31-(0)6-21234586
Servoy Developer
omar
 
Posts: 325
Joined: Sat Feb 12, 2011 4:51 pm
Location: Intrasoft, The Netherlands

Re: another (different) rounding problem

Postby patrick » Fri Sep 22, 2017 10:14 am

We will add that to svyUtils/svyJSUtils so it doesn't get lost.
Patrick Ruhsert
Servoy DACH
patrick
 
Posts: 3655
Joined: Wed Jun 11, 2003 10:33 am
Location: Munich, Germany

Re: another (different) rounding problem

Postby Harjo » Thu Apr 05, 2018 1:08 pm

The story continues:

please do provide this to this method:

round(42.50/100*21)

it wil return 8.92 instead of 8.93 :shock: :shock:

in command console you see that if you do this: =>42.50/100*21
will return: 8.924999999999999


Code: Select all
/**
* Round using exponential notation shifting
*
* @param {Number} value
* @param {Number} precision
*/
function round(value, precision) {
   return Number(Math.round(Number(Math.abs(value)+'e'+precision))+'e-'+precision) * (value < 0 ? -1 : 1)
}


So also this function, is NOT failproof
Harjo Kompagnie
Direct ICT / Servoy Hosting / ServoyCamp
Servoy Certified Developer
Servoy Valued Professional
SAN Developer
User avatar
Harjo
 
Posts: 4290
Joined: Fri Apr 25, 2003 11:42 pm
Location: DEN HAM OV, The Netherlands

Re: another (different) rounding problem

Postby omar » Thu Apr 05, 2018 2:09 pm

Hi Harjo,

That's debatable, imho. The correct answer for rounding 8.924999999999999 is actually 8.92... The problem is that when you calculate 42.50/100*21 Javascript probably has to calculate the answer in two steps and use implicit rounding which we already know is unsuitable for the job. A possible solution is to multiply the inputs that contain decimals by 100 and divide with 100 after obtaining the answer: (4250/100*21)/100 = 8.925 which then correctly rounds to 8.93. Multiplying first also helps: 42.50*21/100 = 8.925.
Intrasoft, Founder
Omar van Galen
[email protected]
+31-(0)6-21234586
Servoy Developer
omar
 
Posts: 325
Joined: Sat Feb 12, 2011 4:51 pm
Location: Intrasoft, The Netherlands

Re: another (different) rounding problem

Postby Harjo » Thu Apr 05, 2018 3:41 pm

your suggestion, is just again a workaound, which you have to think about.
I'm looking for a 100% accurate solution, which always works and calculates the right way.

so far, my simple function, works always in ALL examples above:

Code: Select all
function core_round_money(vValue) {
   if(vValue<0) {
      return Math.round((vValue - 0.00000001) * 100) / 100;
   } else {
      return Math.round((vValue + 0.00000001) * 100) / 100;
   }
}
Harjo Kompagnie
Direct ICT / Servoy Hosting / ServoyCamp
Servoy Certified Developer
Servoy Valued Professional
SAN Developer
User avatar
Harjo
 
Posts: 4290
Joined: Fri Apr 25, 2003 11:42 pm
Location: DEN HAM OV, The Netherlands

Re: another (different) rounding problem

Postby omar » Thu Apr 05, 2018 4:07 pm

So 0.9249999 = 0.92 and 0.92499999 = 0.93? That doesn't make sense to me, sorry.
Intrasoft, Founder
Omar van Galen
[email protected]
+31-(0)6-21234586
Servoy Developer
omar
 
Posts: 325
Joined: Sat Feb 12, 2011 4:51 pm
Location: Intrasoft, The Netherlands

Re: another (different) rounding problem

Postby Harjo » Thu Apr 05, 2018 4:19 pm

the result is what counts for me:
with this method:

Code: Select all
/**
* Round using exponential notation shifting
*
* @param {Number} value
* @param {Number} precision
*/
function round(value, precision) {
   return Number(Math.round(Number(Math.abs(value)+'e'+precision))+'e-'+precision) * (value < 0 ? -1 : 1)
}



round(42.50/100*21) will return 8.92 instead of 8.93

in my case:

Code: Select all
function core_round_money(vValue) {
   if(vValue<0) {
      return Math.round((vValue - 0.00000001) * 100) / 100;
   } else {
      return Math.round((vValue + 0.00000001) * 100) / 100;
   }
}


core_round_money(42.50/100*21) will return correctly 8.93
Harjo Kompagnie
Direct ICT / Servoy Hosting / ServoyCamp
Servoy Certified Developer
Servoy Valued Professional
SAN Developer
User avatar
Harjo
 
Posts: 4290
Joined: Fri Apr 25, 2003 11:42 pm
Location: DEN HAM OV, The Netherlands

Re: another (different) rounding problem

Postby lwjwillemsen » Thu Apr 05, 2018 4:28 pm

I think that in the business (non scientific) area the rounding method of Harjo will do fine.
It's all about the number of significant digits you want or require...

Nice one for Servoy Camp Harjo :wink:
Lambert Willemsen
Vision Development BV
lwjwillemsen
 
Posts: 603
Joined: Sat Mar 14, 2009 5:39 pm
Location: The Netherlands

Re: another (different) rounding problem

Postby ROCLASI » Fri Apr 13, 2018 5:07 pm

Sorry, couldn't help myself.

Must.be.a.oneliner.... ;)


Code: Select all
/**
* @param {Number} value
* @param {Number} precision
*/
function roundNumber(value, precision ) {
    return Math.round( (value + (value < 0 ? -0.00000001 : 0.00000001)) * Math.pow(10, precision)) / Math.pow(10, precision);
}
Robert Ivens
ROCLASI Software Solutions / JBS Group, Partner
SAN Developer / Servoy Valued Professional / Servoy Certified Developer
Twitter: @roclasi / @servoyforge
--
ServoyForge - Building Open Source Software.
PostgreSQL - The world's most advanced open source database.
User avatar
ROCLASI
Servoy Expert
 
Posts: 5285
Joined: Thu Oct 02, 2003 9:49 am
Location: Netherlands/Belgium

Re: another (different) rounding problem

Postby mboegem » Fri Apr 13, 2018 5:12 pm

:lol: :lol: :lol:

You must be a fan of minimised js files... all code in 1 line :wink:
Code: Select all
function roundNumber(value,precision){return Math.round((value+(value<0?-1e-8:1e-8))*Math.pow(10,precision))/Math.pow(10,precision)}
_____________________
Marc Boegem
Solutiative / JBS Group, Partner
• Servoy Certified Developer
• Servoy Valued Professional
• Freelance SAN Developer

Image
User avatar
mboegem
 
Posts: 1445
Joined: Sun Oct 14, 2007 1:34 pm
Location: Hoofddorp, The Netherlands

PreviousNext

Return to Programming with Servoy

Who is online

Users browsing this forum: Bing [Bot] and 5 guests