forums.silverfrost.com Forum Index forums.silverfrost.com
Welcome to the Silverfrost forums
 
 FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

Rounding

 
Post new topic   Reply to topic    forums.silverfrost.com Forum Index -> General
View previous topic :: View next topic  
Author Message
LitusSaxonicum



Joined: 23 Aug 2005
Posts: 2388
Location: Yateley, Hants, UK

PostPosted: Tue Jan 18, 2022 11:37 am    Post subject: Rounding Reply with quote

I think that everyone knows about rounding to the nearest INTEGER from a REAL with the conversion to INTEGER rounding down, so for rounding up you need to add 1, and to round to the nearest, add 0.5 before the conversion.

My issue is with rounding to a specific precision. The context is that in picking a coordinate off a screen, the position is given in pixels, which are INTEGER and therefore of limited precision anyway. Where the screen image represents a physical object which may have dimensions in (say) metres, there has to be a real-world-to-pixel scale factor from which I can determine the real-world coordinates of the point picked. Inevitably, this comes out with a huge string of decimal places. I have found that to round to a particular precision, say millimetres, I can get the effect I want with an internal WRITE, as in:
Code:
      CHARACTER*(2) TEMP_TEXT
      WRITE (TEMP_TEXT,’(F20.3)’) VALUE
      READ (TEMP_TEXT,*) VALUE

It occurs to me that inside the WRITE statement there has to be a rounding algorithm, and I have gone a roundabout way to using it.

So far, so good. The method works if I want to round to a particular number of decimal places, and before anyone says, yes, I know that the binary representation will be inexact. The problem is not solved by this method if I want to round to (say) the nearest 0.2m, 0.25m or 0.5m. My efforts so far do work, but are clumsy.

Is there anyone out there with a mathematics and computing background who knows of a good general purpose rounding algorithm?

Eddie
Back to top
View user's profile Send private message
mecej4



Joined: 31 Oct 2006
Posts: 1884

PostPosted: Tue Jan 18, 2022 1:29 pm    Post subject: Reply with quote

Eddie,

There are probably additional requirements that you have not yet stated, but here is my first attempt. Given integer arrays iX and iY, which contain pixel coordinates, the second part of the following program outputs the corresponding "real world" X and Y coordinates that are "snapped" to the nearest integer multiples of 0.1 and 0.25, respectively.
Code:
program round
implicit none
integer, parameter :: NP = 10
integer i, ix(NP), iy(NP)
real x(NP), y(NP)
real, parameter :: xunit = 0.005, yunit = 0.01  ! real world distance per pixel
real, parameter :: xsnap = 0.1,   ysnap = 0.25  ! smallest discrete distances allowed
call random_number(x)
call random_number(y)
x = x*640; y = y*480
ix = nint(x); iy = nint(y) ! ix and iy are artifically generated pixel coordinates
! Eddie's real app starts here, with ix, iy generated by mouse clicks, etc.
print '(i2,2i8)',(i,ix(i),iy(i),i=1,NP)
print *
x = nint(ix*xunit/xsnap)*xsnap
y = nint(iy*yunit/xsnap)*ysnap
print '(i2,2F10.2)',(i,x(i),y(i),i=1,NP)
end program

The output:
Code:
 1     431       3
 2     212     360
 3      94     260
 4     475     203
 5     220     209
 6      58     263
 7     471     127
 8     335      43
 9     393      77
10     429     350

 1      2.20      0.00
 2      1.10      9.00
 3      0.50      6.50
 4      2.40      5.00
 5      1.10      5.25
 6      0.30      6.50
 7      2.40      3.25
 8      1.70      1.00
 9      2.00      2.00
10      2.10      8.75


Last edited by mecej4 on Tue Jan 18, 2022 2:55 pm; edited 1 time in total
Back to top
View user's profile Send private message
LitusSaxonicum



Joined: 23 Aug 2005
Posts: 2388
Location: Yateley, Hants, UK

PostPosted: Tue Jan 18, 2022 2:54 pm    Post subject: Reply with quote

Thanks Mecej4,

Not quite it, though, because after I have got the pixel coords, I convert to real world coordinates, and it's those I want to round.

Hence, after the random number generation and multiplying by the VGA 640x480 in your demo, I get:

1 430.76504517 43.13289642 (printing 8 decimal places)

and the output I want, rounding to say the nearest 0.1 is:

1 430.8 43.1

or to 0.25 is:

1 430.75 43.25

and so on.

Thanks for your suggestion, which provides me with food for thought.

Eddie
Back to top
View user's profile Send private message
mecej4



Joined: 31 Oct 2006
Posts: 1884

PostPosted: Tue Jan 18, 2022 3:16 pm    Post subject: Reply with quote

Please rethink your response!

You don't start with 430.765 pixels, etc. You start with integers.

You have to apply a linear transformation to scale and shift the integer valued pixel coordinates to real world coordinates. You then snap the real coordinates to the chosen grid.

The expressions ix*xunit and iy*yunit are the real world coordinates. Dividing by xsnap, rounding and then multiplying by xsnap perfoms the snapping operation to the x coordinates, and similarly ysnap is applied for the y coordinates.

Perhaps you can make up an example with a small number of input pixel coordinates and the desired output real coordinates snapped to a grid.

----
However, if the customer is always right, here goes:

Code:
program snap
implicit none
real :: x(2) = [430.765, 43.133]
real :: snap = 0.25
print '(2F8.2)',nint(x/snap)*snap
end
Back to top
View user's profile Send private message
LitusSaxonicum



Joined: 23 Aug 2005
Posts: 2388
Location: Yateley, Hants, UK

PostPosted: Wed Jan 19, 2022 12:30 pm    Post subject: Reply with quote

Hi Mecej4,

I hadn't realised I was a customer. What do you want your fee in? I have a stock of pre-decimal coins and old Italian Lira.

I see now what you did, I was confused by 2 axis scaling - I have the same scales in both axes (it's a real object, not a graph/chart). Also, the object is centred in the graphics workspace (so there are offsets in both axes) , and being ClearWin/Windows, y is measured downwards, which I know from experience of myself and others isn't the upper right quadrant that many engineers like myself are more comfortable in. Hence I hadn't imagined the 'de-scaling' being done in the same breath as the rounding.

There is an additional subtlety about whether or not the centre or corner of a pixel is the critical start point when descaling, so it might not necessarily be an integer number of pixels (is it the pixel number off the graphics area -minus 0.5?).

Doesn't it have to be:

Code:
nint (x/snap+0.5)*snap


to both round up or down to nearest?

Incidentally, I'm doing it in REAL*8, not REAL*4 where there isn't enough decimal places of precision - but you probably guessed that.

What I described as my clumsy first attempts consisted of only operating on the decimal part of the real-world coordinates .

Thanks for thinking about it.

Eddie
Back to top
View user's profile Send private message
mecej4



Joined: 31 Oct 2006
Posts: 1884

PostPosted: Wed Jan 19, 2022 3:16 pm    Post subject: Reply with quote

The advantage of using the NINT function instead of the INT function is that you do not have to tinker with the +0.5 or -0.5, etc.

For x >= 0, NINT(x) = INT(x+0.5)

For x < 0, NINT(x) = INT(x-0.5)

Loosely stated, INT is for chopping, NINT for rounding.

You have to decide for yourself the convention for the location of a pixel (which of its four corners, the center, or the four centers of its four edges, as appropriate for your intended application.
Back to top
View user's profile Send private message
LitusSaxonicum



Joined: 23 Aug 2005
Posts: 2388
Location: Yateley, Hants, UK

PostPosted: Wed Jan 19, 2022 4:15 pm    Post subject: Reply with quote

Yep, didn't realise what NINT did - I thought it was yet another botch of things that have been there forever and was an alias for INT rather than INT dressed up so as to change its personal pronouns.

Quote:
You have to decide for yourself the convention for the location of a pixel (which of its four corners, the centre or the four centres of its four edges, as appropriate for your intended application.


... which is why I started by asking for rounding only, as I was taking care of that already!

Anyway, I learned something today, which shows that some old dogs can still learn new tricks, even if they are simple ones!

Many thanks

Eddie
Back to top
View user's profile Send private message
Display posts from previous:   
Post new topic   Reply to topic    forums.silverfrost.com Forum Index -> General All times are GMT + 1 Hour
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group