Recent

Author Topic: Problem with round function  (Read 9166 times)

Steven Pietrobon

  • New Member
  • *
  • Posts: 20
Problem with round function
« on: August 29, 2019, 03:31:09 am »
I'm getting a strange output from the round function using fpc-3.0.4.i386-win32 on Windows XP. If I perform the following

round(I+0.5)

where I is an integer, then this happens:

I is even and positive: output is I! For example round(6.5) = 6. Result should be 7! I get the correct result if I is odd.

I is odd and negative: output is -I+1. For example round(-2.5) = -2. Result should be -3! I get the correct result if I is even.

According to my turbo Pascal book round should do the following:

"Round(x: real)

x is a real-type expression. Round returns a longint value that is the value of x rounded to the nearest whole number. If x is exactly halfway between two whole numbers, the result is the number with the greatest absolute magnitude. A runtime error occurs if the rounded value of x is not within the longint range."

Attached is a little program that tests this.

My question is, does anyone else get the same output?
« Last Edit: August 29, 2019, 03:50:28 am by Steven Pietrobon »

lucamar

  • Hero Member
  • *****
  • Posts: 4219
Re: Problem with round function
« Reply #1 on: August 29, 2019, 04:12:49 am »
According to the RTL documentation:

Quote from: Reference for unit: System
In the case of .5, the algorithm uses "banker's rounding": .5 values are always rounded towards the even number.

IIRC, that has been the case since the times of Turbo Pascal.
Turbo Pascal 3 CP/M - Amstrad PCW 8256 (512 KB !!!) :P
Lazarus/FPC 2.0.8/3.0.4 & 2.0.12/3.2.0 - 32/64 bits on:
(K|L|X)Ubuntu 12..18, Windows XP, 7, 10 and various DOSes.

Handoko

  • Hero Member
  • *****
  • Posts: 5129
  • My goal: build my own game engine using Lazarus
Re: Problem with round function
« Reply #2 on: August 29, 2019, 04:39:42 am »
Hello Steven Pietrobon,
Welcome to the forum.

Actually there are about 10 kinds (or maybe more) of rounding, and as lucamar already explained that RTL uses banker's rounding.

For more information you can read here:
https://en.wikipedia.org/wiki/Rounding
https://www.freepascal.org/docs-html/rtl/system/round.html

~edit~

I can't find information about Turbo Pascal's round function. But according to this page, it said Pascal language uses banker's rounding:
https://en.wikipedia.org/wiki/Pascal_%28programming_language%29#Data_types
« Last Edit: August 29, 2019, 04:47:41 am by Handoko »

Steven Pietrobon

  • New Member
  • *
  • Posts: 20
Re: Problem with round function
« Reply #3 on: August 29, 2019, 05:41:40 am »
Thankyou everyone for your replies.

Surely you know better than to trust Wikipedia! :-)

I have an original copy of Borland's Turbo Pascal 4.0 book from 1987. It does not say that round uses banker's rounding. It is as described in my original post. Attached is a scan of the page.

Steven Pietrobon

  • New Member
  • *
  • Posts: 20
Re: Problem with round function
« Reply #4 on: August 29, 2019, 06:59:12 am »
The same definition is also given Version 5.0 (page 349, pdf page 368)

https://archive.org/details/bitsavers_borlandturVersion5.0ReferenceGuide1989_16033215/page/n367
« Last Edit: August 29, 2019, 07:01:26 am by Steven Pietrobon »

RAW

  • Hero Member
  • *****
  • Posts: 868
Windows 7 Pro (x64 Sp1) & Windows XP Pro (x86 Sp3).

Steven Pietrobon

  • New Member
  • *
  • Posts: 20
Re: Problem with round function
« Reply #6 on: August 29, 2019, 07:25:14 am »
So what does this mean? Will Free Pascal correct round to its original definition? Add a switch that allows the original definition to be used? Or just ignore the problem? Not doing anything means that original Turbo Pascal code may not work correctly due to round being implemented incorrectly.
« Last Edit: August 29, 2019, 07:44:03 am by Steven Pietrobon »

Handoko

  • Hero Member
  • *****
  • Posts: 5129
  • My goal: build my own game engine using Lazarus
Re: Problem with round function
« Reply #7 on: August 29, 2019, 07:45:58 am »
If you think Free Pascal's round function is incorrect, you can submit a report to the bugtracker forum:
http://bugs.freepascal.org/set_project.php?project_id=6

But I don't think the developer team will make any changes. Most users here already knew FPC's round uses banker's rounding and we all have no issue with it. Also, changing how the current round function behaves, may cause many existing source codes work not as what it should be. It can be a nightmare.

I hate to say but it is true:
FPC is not Turbo Pascal.

If you're unsure about how certain function works, you should check the FPC/Lazarus documentation first (not TP nor Delphi). Here are some links that worth to be bookmarked:

(Free) Pascal reference guide:

http://freepascal.org/docs-html/current/ref/ref.html

If you're new in Pascal programming? Try these:
http://www.pascal-programming.info/index.php
http://www.taoyue.com/tutorials/pascal/index.html

First time using Lazarus? Read here:
http://wiki.lazarus.freepascal.org/Lazarus_Tutorial

Lazarus IDE tricks (some are with animation):
http://wiki.freepascal.org/New_IDE_features_since

List of tutorials with wide range of topics (graphics, database, printer, web, etc):

http://wiki.freepascal.org/Lazarus_Documentation#Lazarus.2FFPC_.28Free_Pascal.29
http://wiki.freepascal.org/Category:Tutorials

Some cool Pascal tricks:

http://lazplanet.blogspot.co.id/

Lazarus video tutorials:
https://wiki.lazarus.freepascal.org/Lazarus_videos
https://devstructor.com/index.php?page=tutorials

Using examples that bundled with Lazarus installation:
Lazarus main menu > Tools > Example Projects > on the Project filter box, type the keyword for example: "sql"
Note:
Don't run it directly from there but save them first to a new location.

~edit~

I've just found the discussion about incompatibility between FPC's and TP's round function, it has been reported here:
https://bugs.freepascal.org/view.php?id=35626
« Last Edit: August 29, 2019, 08:20:40 am by Handoko »

BrunoK

  • Sr. Member
  • ****
  • Posts: 452
  • Retired programmer
Re: Problem with round function
« Reply #8 on: August 29, 2019, 09:09:25 am »
The round functions means so many things that you should write your own and use it in the future so you know what it does.
That's what I have done for the last 40 years either in code and also in EXCEL.

Bankers rounding is not natural to most people /  users. It is OK if it is specified but even in accountancy firms they didn't use it.

By the way the old pascal did it differently from more recent versions of Delphi, the recent versions have so many variants that you are much better of writing your own.

Handoko

  • Hero Member
  • *****
  • Posts: 5129
  • My goal: build my own game engine using Lazarus
Re: Problem with round function
« Reply #9 on: August 29, 2019, 09:50:56 am »
The round functions means so many things that you should write your own and use it in the future so you know what it does.
That's what I have done for the last 40 years either in code and also in EXCEL.

I ever worked at a software house briefly, they wrote their own rounding function too.

Thaddy

  • Hero Member
  • *****
  • Posts: 14197
  • Probably until I exterminate Putin.
Re: Problem with round function
« Reply #10 on: August 29, 2019, 09:54:22 am »
I ever worked at a software house briefly, they wrote their own rounding function too.
Most do: it also depends on the FPU rounding mode (to complicate things further) So even the docs are not always correct, but the default is sufficiently documented.
Specialize a type, not a var.

Steven Pietrobon

  • New Member
  • *
  • Posts: 20
Re: Problem with round function
« Reply #11 on: August 29, 2019, 10:10:57 am »
Do you think Free Pascal would be willing to add a switch to correct the round function, e.g., ppc386 -Borland?

Thaddy

  • Hero Member
  • *****
  • Posts: 14197
  • Probably until I exterminate Putin.
Re: Problem with round function
« Reply #12 on: August 29, 2019, 10:27:01 am »
Do you think Free Pascal would be willing to add a switch to correct the round function, e.g., ppc386 -Borland?
No need: you can switch the rounding mode of the FPU both in Delphi and freepascal.
Specialize a type, not a var.

wp

  • Hero Member
  • *****
  • Posts: 11853
Re: Problem with round function
« Reply #13 on: August 29, 2019, 10:27:56 am »
There is already a switch {$mode TP}, but it also does Banker's rounding (unlike TP7.0). I think this is a bug here clearly. You should file a bug report.

wp

  • Hero Member
  • *****
  • Posts: 11853
Re: Problem with round function
« Reply #14 on: August 29, 2019, 11:16:19 am »
You can switch the rounding mode of the FPU both in Delphi and freepascal.
This will not make the expected results. Rounding is too complex to be mapped to the four RoundModes. One problem is in negative numbers. In my math feeling (which may be wrong...) I would expect negative values to round like the positive ones, i.e. Round(-0.5) = -1, Round(-1.5) = -2, etc. I won't get this result whichever value is applied to RoundMode (even for the positive values the result is not as expected). Therefore, the only way to guarantee the result required is to write your own rounding function.
Code: Pascal  [Select][+][-]
  1. program Project1;
  2.  
  3. uses
  4.   Math;
  5.  
  6. // Round half away from zero rule
  7. // https://en.wikipedia.org/wiki/Rounding#Round_half_away_from_zero
  8. function MyRound(x: Double): Integer;
  9. begin
  10.   if x >= 0 then
  11.     Result := Trunc(x + 0.5)
  12.   else
  13.     Result := -Trunc(-x + 0.5);
  14. end;
  15.  
  16. begin
  17.   WriteLn('RoundMode rmNearest');
  18.   SetRoundMode(rmNearest);
  19.   WriteLn(Round(-1.5));
  20.   WriteLn(Round(-0.5));
  21.   WriteLn(Round(0.5));
  22.   WriteLn(Round(1.5));
  23.  
  24.   WriteLn('RoundMode rmUp');
  25.   SetRoundMode(rmUp);
  26.   WriteLn(Round(-1.5));
  27.   WriteLn(Round(-0.5));
  28.   WriteLn(Round(0.5));
  29.   WriteLn(Round(1.5));
  30.  
  31.   WriteLn('RoundMode rmDown');
  32.   WriteLn(Round(-1.5));
  33.   WriteLn(Round(-0.5));
  34.   WriteLn(Round(0.5));
  35.   WriteLn(Round(1.5));
  36.  
  37.   WriteLn('RoundMode rmTruncate');
  38.   SetRoundMode(rmTruncate);
  39.   WriteLn(Round(-1.5));
  40.   WriteLn(Round(-0.5));
  41.   WriteLn(Round(0.5));
  42.   WriteLn(Round(1.5));
  43.  
  44.   WriteLn('MyRound');
  45.   WriteLn(MyRound(-1.5));
  46.   WriteLn(MyRound(-0.5));
  47.   WriteLn(MyRound(0.5));
  48.   WriteLn(MyRound(1.5));
  49.  
  50.   ReadLn;
  51. end.

Output:
Code: [Select]
RoundMode rmNearest
-2
0
0
2
RoundMode rmUp
-2
0
0
2
RoundMode rmDown
-2
0
0
2
RoundMode rmTruncate
-2
0
0
2
MyRound
-2
-1
1
2

 

TinyPortal © 2005-2018