SetRoundMode (rmUp) and rounding off "round" values ​​like 10 leads to 10 0001, how did it happen?

This code:

SetRoundMode(rmUp); Memo1.Lines.Add(CurrToStr(SimpleRoundTo(10))); 

Results at 10,0001.

I just do not understand.

I thought rmUp would do something like: from 10.0001 to 11, but not from 10 to 10.0001.

Can anyone explain why this is happening?

Thanks.

+3
source share
4 answers

SimpleRoundTo works as follows:

  • Divide the input by 10 -x where x is the number of decimal places to store as a result.
  • Add 0.5 to this product.
  • Truncate the amount.
  • Multiply by 10 -x .

The result is a floating point value. As with most floating point values, the result will not be accurate, although in your case you start with the exact value. The number of decimal places indicated for SimpleRoundTo is negative, so the divisor in step 1 for your input example would ideally be 0.01. But this cannot be represented exactly as a floating-point number, so when 10 / 0.01 is calculated in step 1, the result is not exactly 1000. The result in step 3 will be exactly 1000, however, therefore, the inaccuracy of the separation does not matter. However, the inaccuracy of the multiplication in step 4. This product will not be accurate. He will be a little higher than 10.

So, SimpleRoundTo returns a slightly higher value, and since you indicated that rounding should increase, converting the Extended CurrToStr result to Currency CurrToStr will result in an exact 10.0001.

Currency values ​​are accurate; they are a fixed-point value, an integer scalable by four decimal places.

+13
source

I would use the Round () function if rounding up the bankers is ok. it returns an integer.

if you don't like rounding a banker, you can use this:

 // use this to not get "banker rounding" function HumanRound(X: Extended): integer; // Rounds a number "normally": if the fractional // part is >= 0.5 the number is rounded up (see RoundUp) // Otherwise, if the fractional part is < 0.5, the // number is rounded down // RoundN(3.5) = 4 RoundN(-3.5) = -4 // RoundN(3.1) = 3 RoundN(-3.1) = -3 begin // Trunc() does nothing except conv to integer. needed because return type of Int() is Extended Result := Trunc(Int(X) + Int(Frac(X) * 2)); end; 

my message here is a little off topic, but still informative.

I examined this in detail, since I did not need to use banker's rounding. here are my findings. as far as I can see, this still does not eliminate the rounding of bankers.

 Value Meaning rmNearest Rounds to the closest value. rmDown Rounds toward negative infinity. rmUp Rounds toward positive infinity. rmTruncate Truncates the value, rounding positive numbers down and negative numbers up. rmNearest // default 0.500 0 1.500 2 2.450 2 2.500 2 2.550 3 3.450 3 3.500 4 3.550 4 rmDown 0.500 0 1.500 1 2.450 2 2.500 2 2.550 2 3.450 3 3.500 3 3.550 3 rmUp 0.500 1 1.500 2 2.450 3 2.500 3 2.550 3 3.450 4 3.500 4 3.550 4 rmTrunc 0.500 0 1.500 1 2.450 2 2.500 2 2.550 2 3.450 3 3.500 3 3.550 3 uses math, sysutils, clipbrd; var s:string; procedure trythis(sMode:string); procedure tryone(d:double); begin s:=s+Format('%1.3f %d%s',[d,Round(d),#13+#10]); end; begin s:=s+#13#10+sMode+#13#10; tryone(0.50); tryone(1.50); tryone(2.45); tryone(2.50); tryone(2.55); tryone(3.45); tryone(3.50); tryone(3.55); end; begin s:=inttostr(integer(GetRoundMode)); SetRoundMode(rmNearest); trythis('nearest'); SetRoundMode(rmDown); trythis('down'); SetRoundMode(rmUp); trythis('up'); SetRoundMode(rmTruncate); trythis('trunc'); clipboard.astext:=s; end. 
+4
source

The return values ​​from the SimpleToRound calculation are also Double and should never be trusted rounding. Truncate the value before conversion; it should do the job!

Memo1.Lines.Add (CurrToStr (Trunc (SimpleRoundTo (10))));

+2
source

The Ceil (): Integer function should give you the answer you want for values> 0. If <0, you may need to use floor () instead, depending on your desired behavior.

+1
source

All Articles