POV-Ray : Newsgroups : povray.newusers : mod() and floating point division woes. :( Server Time: 19 Dec 2018 11:41:21 GMT
 mod() and floating point division woes. :( (Message 1 to 6 of 6)
 From: Bald Eagle Subject: mod() and floating point division woes. :( Date: 3 Sep 2018 00:30:00 Message:
```So....

I _just_ want to use mod (N, 0.1) in a loop of #for(N, 0, 1, 0.02).

What's a good reliable way to implement an fmod() equivalent?
Do I need to write a macro, or is there a straightforward function (){} that I
can use?

Sorry to be grappling with "computer science math" again.

Some of the values I get are "0", others are "0.1".
I'm challenged by the wide disparity between the two possibilities, and can't
get anything to work reliably, especially when I try to use the mod(A, B) result
in a select () statement.
```
 From: jr Subject: Re: mod() and floating point division woes. :( Date: 3 Sep 2018 01:25:00 Message:
```hi,

"Bald Eagle" <cre### [at] netscapenet> wrote:
> I _just_ want to use mod (N, 0.1) in a loop of #for(N, 0, 1, 0.02).

the manual shows an explicit int() in the formula. (section 3.3.1.5.3).

use integers for loop control + scale to taste, for the mod scale beforehand +
convert the result into the fractional value as needed.

(personal opinion + based on ignorance of POV's inner workings  :-))

regards, jr.
```
 From: dick balaska Subject: Re: mod() and floating point division woes. :( Date: 3 Sep 2018 02:02:12 Message: <5b8c9624\$1@news.povray.org>
```On 09/02/2018 09:20 PM, jr wrote:
> hi,
>

>
> use integers for loop control + scale to taste,
>

What he said.

I believe clipka told you the same thing recently. Woe be to he who
chooses to ignore the mighty clipka.

--
dik
Rendered 1024 of 921600 pixels (0%)
```
 From: Bald Eagle Subject: Re: mod() and floating point division woes. :( Date: 3 Sep 2018 12:35:00 Message:
```dick balaska <dic### [at] buckosoftcom> wrote:

> What he said.
>
> I believe clipka told you the same thing recently. Woe be to he who
> chooses to ignore the mighty clipka.

Yes, yes - it wasn't ignored, it just wasn't fully interpreted and implemented.

I hate having 35 conversion factors for this that & the other thing.
And this was an entirely different loop that I was "extracting a value out of"
so it wasn't on the #for-#end highway, it was in the SDL suburb.
So it "seemed" different.

I'd say that this has more to do with mod(A,B) than with the loop.

I mean, there are going to be places where you need to do some floating point
math and use the result as directly as possible, otherwise you're going to be
five nested loops deep into code with 7 include files, and then the suggestion
that you "just" rewrite the code to use integers become - ridiculous.

At some point 1/5 ought to "equal 0.2" in an absolute, Boolean, true/false way,
and not some - well it's actually kinda sorta 0.2 +/- E way.

And I will point out that in diligently trying to find a suitable answer myself,
many "computer guys" in many fora have discussed mod and fmod and how it should
work just as well for floating point arguments as for integers.
And there were as many different answers as there were responders to the OP who
all argued with each other.  :|

Then there's --- the POV-Ray source code itself, where I found this:
https://github.com/POV-Ray/povray/blob/master/source/base/mathutil.h

So, I'm just trying to learn about the basics of the floating point math
problems and how to solve them, rather than just stay ignorant and try to do it
"the easy way" by avoiding them, until I one day am faced with one I HAVE to
solve.

"Don't do that" doesn't work with me.

"Here's how you deal with that kind of problem when you come across it" is much
more in line with the way I think and do things, because I'm always going to be
drilling down to the fundamental first principles and trying to understand them
at some point.

(Hugs, you little psychopath, you!)
"When Murphy crunched the numbers, he found Connecticut was the most
psychopathic state per capita, followed by California, New Jersey, and New
York/Wyoming (which were equally tied in fourth place)."

-------------------------------------------------------------------------------

// wrap floating-point value into the range [0..upperLimit);
// (this is equivalent to fmod() for positive values, but not for negative ones)
template<typename T>
inline T wrap(T val, T upperLimit)
{
T tempVal = fmod(val, upperLimit);
// NB: The range of the value computed by fmod() should be in the range
// but on some architectures may actually be in the range [0..upperLimit].

if (tempVal < T(0.0))
{
// For negative values, fmod() returns a value in the range
[-upperLimit..0];
// transpose it into the range [0..upperLimit].
tempVal += upperLimit;
}

// for negative values (and also for positive values on systems that
internally use higher precision
// than double for computations) we may end up with value equal to
upperLimit (in double precision);
// make sure to wrap these special cases to the range [0..upperLimit) as
well.
if (forcePrecision<double>(tempVal) >= upperLimit)
tempVal = T(0.0);

// sanity check; this should never kick in, unless wrap() has an
implementation error.
POV_MATHUTIL_ASSERT((tempVal >= 0.0) && (tempVal < upperLimit));

return tempVal;
}
```
 From: Alain Subject: Re: mod() and floating point division woes. :( Date: 3 Sep 2018 18:25:34 Message: <5b8d7c9e\$1@news.povray.org>
```Le 18-09-02 Ã  20:27, Bald Eagle a Ã©critÂ :
>
> So....
>
> I _just_ want to use mod (N, 0.1) in a loop of #for(N, 0, 1, 0.02).
>
> What's a good reliable way to implement an fmod() equivalent?
> Do I need to write a macro, or is there a straightforward function (){} that I
> can use?
>
> Sorry to be grappling with "computer science math" again.
>
> Some of the values I get are "0", others are "0.1".
> I'm challenged by the wide disparity between the two possibilities, and can't
> get anything to work reliably, especially when I try to use the mod(A, B) result
> in a select () statement.
>
>
>

I would multiply everything by 10 or 100, calculate the mod(A,B), then
divide by 10 or 100.

mod(A,B) stand for the remainder of an integer division. It don't play
well with a non-integer divisor. At least, that's what I tend to assume.

You can use something like :
#declare Something = mod(N*10, 1)/10;

This is functionally identical to what you want.
```
 From: clipka Subject: Re: mod() and floating point division woes. :( Date: 4 Sep 2018 00:13:19 Message: <5b8dce1f\$1@news.povray.org>
```Am 03.09.2018 um 14:32 schrieb Bald Eagle:

> At some point 1/5 ought to "equal 0.2" in an absolute, Boolean, true/false way,
> and not some - well it's actually kinda sorta 0.2 +/- E way.

The problem is rarely with just a single mathematical operation - a
proper implementation of the C/C++ floating-point library functions will
alway compute the exact result, rounded by some standardized mechanism.
(That rounding mode is more or less arbitrary, but is consistent. So for
instance an implementation may round all results towards zero. Or it may
round all results towards negative infinity.)

So while it is not guaranteed that 1/5 can be represented exactly, nor
whether the result will be a bit too high or too low, it is guaranteed
to use the same representation as converting the string "0.2" to
floating point, or computing 3/15. In other words, the results are
ROUND(1/5), ROUND(0.2) and ROUND(3/15), respectively, where ROUND() is
the implementation's rounding scheme. So since A=B => ROUND(A)=ROUND(B),
such results compare perfectly equal.

The problem arises when the inexactly-represented interim results of one
operation are used as parameter to another operation, and /then/ the end
result compared to a value obtained differently. For example, it is
/not/ guaranteed that the result of (1/5)+(2/5) will equal 3/5, because
the former will be approximated as ROUND(ROUND(1/5)+ROUND(2/5)) =
ROUND((1/5+ERROR1)+(2/5+ERROR2)) = ROUND(1/5+ERROR1+ERROR2), while the
latter will just be ROUND(1/5).

Worst offenders are additions of numbers with significantly different
magnitudes, by the way.

> Then there's --- the POV-Ray source code itself, where I found this:
> https://github.com/POV-Ray/povray/blob/master/source/base/mathutil.h

Some fun facts in there, eh?
Learned those nasty details the hard way.

Sometimes I think we should really be doing math on ranges rather than
single floating point numbers; that way we can really tell how precise
any given computed value is, and testing whether two results are equal
would really mean testing if the computed ranges have at least one value
in common.
```