3
$\begingroup$

Why is the result of this calculation 0 and not 1?

enter image description here

$\endgroup$
4
  • $\begingroup$ My quess is that somehow your value ends up 0.999999 and floor rounds it down to 0, but I would like to know why as well $\endgroup$
    – MikoCG
    Aug 6 at 9:39
  • 1
    $\begingroup$ If you switch to cycles and set the shading mode to 'rendered' it works as expected. I guess it's a current limitation of Eevee...? Not sure. Otherwise might worth to file a bug report. $\endgroup$
    – brockmann
    Aug 6 at 9:43
  • $\begingroup$ I tried to recreate it and it shows black in both eevee and cycles $\endgroup$
    – MikoCG
    Aug 6 at 9:54
  • $\begingroup$ I got the same result as @brockmann - it shows white in Cycles, but black in Eevee. The problem seems to be the Floor node. If I mute it, the result is white in Eevee, too. If I render it without Floor and check the RGB values in the render result, they are all 1.0000 which should be white with Floor as well. Maybe there is a floating point issue and somehow it is 0.9999999... instead of 1 or it's a bug in Eevee. Also if I set the value to 10.000001 which is shown as 10.000 it works in Eevee. $\endgroup$ Aug 6 at 10:01
5
$\begingroup$

This is caused by accuracy problems of floating point numbers. Those problems [typically?] don't occur with small whole numbers like 10.0, as you can see for yourself here:

IEEE-754 Floating Point Converter

You can also test your node setup by disconnecting Math > Modulo and inputting 10.0 manually as the first Value of the Math > Divide node. This shows the problem happens inside the modulo node.

I'm not well versed in the Blender source arcane, but it seems the source of that node is in COM_MathBaseOperation.cpp

void MathModuloOperation::executePixelSampled(float output[4],
                                              float x,
                                              float y,
                                              PixelSampler sampler)
{
  float inputValue1[4];
  float inputValue2[4];

  this->m_inputValue1Operation->readSampled(inputValue1, x, y, sampler);
  this->m_inputValue2Operation->readSampled(inputValue2, x, y, sampler);

  if (inputValue2[0] == 0) {
    output[0] = 0.0;
  }
  else {
    output[0] = fmod(inputValue1[0], inputValue2[0]);
  }

  clampIfNeeded(output);
}

However, when I try to fmod(10.0, 100.0) in C++:

float numer = 10.0, denom = 100.0;
float modded = fmod(numer, denom);
float floored = floor(modded);

I get correct results:

So I suspect that behind the scenes, the numbers aren't evaluated as presented in the node setup. Perhaps they are scaled down for some reason?

float numer = 0.01, denom = 0.1;
float modded = fmod(numer, denom);

Just a guess here.

I think in order to stay sane, you should always assume that your number may randomly increase or decrease by the smallest possible step at any point, so think of it as randomly increasing/decreasing by 0.00000001 and work around that.

As a bonus, try to set your divisor in the Math > Divide node to 9.999999. Once you test it and see you get a white material, click on the value, change nothing, and press Enter.

$\endgroup$
4
  • $\begingroup$ Perhaps a small anecdote, I remember when I wrote a shader in Adobe Flash AGAL and a comparison with a number worked as expected on my desktop GPU, but failed in the CPU emulation mode on my old laptop. Just an anecdotal evidence to support my second last paragraph. $\endgroup$ Aug 6 at 10:24
  • $\begingroup$ nope the result is 10... I just checked within blender. $\endgroup$
    – BlackCube
    Aug 7 at 1:58
  • $\begingroup$ I'm sorry, I had a brain fade yesterday and was proposing a nonsensical argument. I'm going to delete my comments. $\endgroup$ Aug 7 at 13:48
  • $\begingroup$ @MartyFouts no problem, cheers! $\endgroup$ Aug 7 at 14:02

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.