Division (Whole and Remainder) Is Incorrect

I’m Having a problem with the Division (Whole and Remainder) Node in Blueprint. it will only give the correct answers to one of the outputs of the return value pin, any other pins connected to if seams to receive -1 or +1 from the correct result.

For Example Dividend of 2 and Divisor of 4 the Output Should be Return Value of 2 and Remainder of 0. This is what happens for one of the other nodes connected to the Return Value node but for other node they receive a different incorrect answer.

This is happening on version 4.5.1 of Unreal engine 4

Any chance you can post a screenshot of your blueprint?
I’ve attempted to reproduce but can’t replicate your results.
Also bear in mind that you currently have things around the wrong way with regards dividend and divisor - your example cited above would try to divide 2 by 4, which returns 0 and has the remainder of 2. The tooltip for the node itself appears to be incorrect, which I’ll see about fixing.

Hey thanks for the fast reply here is my set up

its a little messy but i did what you said about swapping the numbers around but the results are still not right i know for a fact that the number going in to the node is 4 so the result should be return value of 2 no remainder and i get that being set to the array you can see in the image but after that i set a variable to the return value as well but for some reason that variable is being set as 0, and it does this no matter what the input number is or the way the node gets it (even if i manually enter it to the node)

Bump…

Test in a new blueprint template or something else similar with a simple blueprint like the following:
link text

This works fine for me - I get expected output for both calls to Print String.
You’ll need to eliminate other areas of your Blueprint to try to ascertain if something else is modifying the variable.

Hey I’m not sure why but putting the node in a function of its own seamed to fix my results not sure why, thanks for the help twiddle :slight_smile:

I actually have noticed that it is not really dividing the dividend by the divisor, but subtracting it, if I put it 8 for the dividend and 7 as the divisor I get 1 as the remainder instead of .142857142857143 as the remainder.
This is engine version 4.8.3

I just ran afoul of this defect and am necroing this thread as it’s Google’s most prominent result.

To validate what I was seeing, I created the following test and inspected the values during PIE as well as printing them to the log.

It seems to be a long running issue with the underlying C++ specifically;

  • When BP calls the underlying UKismetMathLibrary::FMod(double Dividend, double Divisor, double& Remainder); the parameters acquire epsilon difference (-4e-17 less than the passed in 0.7f in my case.)
  • The problem occurs on the reliance on the FMath::FloorToInt32() which the epsilon affects resulting in a ‘rounding down’ to 13.

//Note: the float version of the function is deprecated and defaults to the double variant.
KismetMathLibrary.cpp

int32 UKismetMathLibrary::FMod(double Dividend, double Divisor, double& Remainder)
{
	int32 Result;
	if (Divisor != 0.f)
	{
		const double Quotient = Dividend / Divisor;
		Result = (Quotient < 0.f ? -1 : 1) * FMath::FloorToInt32(FMath::Abs(Quotient));
		Remainder = FMath::Fmod(Dividend, Divisor);
	}
	else
	{
		FFrame::KismetExecutionMessage(TEXT("Attempted modulo 0 - returning 0."), ELogVerbosity::Warning, DivideByZeroWarning);

		Result = 0;
		Remainder = 0.f;
	}

	return Result;
}

“Amusingly” enough, UKismetMathLibrary::FMod internally uses FGenericPlatformMath::Fmod which internally uses corecrt_math.h’s C implementation of fmod which does calculate the remainder correctly when watched. Then somewhere onroute back to the BP that correct value get’s mixed up with the Divisor’s value…

Anyway, here’s a rudimentary “fix” along with basic test that passes all but the 1e6 / 3 test case. @twiddle I’d love for some input incase I’ve missed something obvious.

/-----/
Edit: See my 3rd post (below) for an improved variant that passes all test cases and takes advantage of the compiler to avoid annoyances with precision.
/-----/

Flawed 1st attempt - Ignore
#define EPSILON 0.0001f

UCLASS(meta = (BlueprintThreadSafe))
class VR_BASE_API UMathBPFL : public UBlueprintFunctionLibrary {
	GENERATED_BODY()

public:
	/// <summary>Returns the number of times the divisor goes into the dividend along with the remainder.</summary>
	UFUNCTION(BlueprintCallable, BlueprintPure, Category = "Math", meta = (DisplayName = "Division (Whole, Remainder)"))
	static void Division(float dividend, float divisor, float& outWhole, float& outRem) {
		if (divisor != 0.0f) {
			const float quotient = dividend / divisor;
			if (quotient >= 0) {
				outWhole = FMath::Floor(quotient);
			} else {
				outWhole = FMath::CeilToFloat(quotient);
			}

			outRem = quotient - outWhole;

		} else {
			UE_LOG(MathExtensions, Warning, TEXT("Attempted to divide by zero - Returning 0 instead of collapsing the universe."));
			outWhole = 0.0f;
			outRem = 0.0f;
		}
	}

   UFUNCTION(BlueprintCallable, Category = "Math", meta = (DisplayName = "Test Division"))
   static void TestDivision() {
      struct TestCase {
         const FString description;
         float dividend;
         float divisor;
         float expectedWhole;
         float expectedRem;
      };

      TestCase cases[] = {
         //Standard cases
         {TEXT("5 / 2"), 5.0f, 2.0f, 2.0f, 0.5f},
         {TEXT("2 / 5"),  2.0f, 5.0f, 0.0f, 0.4f},
         {TEXT("-5 / 2"),  -5.0f, 2.0f, -2.0f, -0.5f},
         {TEXT("-2 / 5"),  -2.0f, 5.0f, 0.0f, -0.4f},
         {TEXT("-5 / -2"),  -5.0f, -2.0f, 2.0f, 0.5f},
         {TEXT("-2 / -5"),  -2.0f, -5.0f, 0.0f, 0.4f},
         {TEXT("0.7 / 0.05"),  0.7f, 0.05f, 14.0f, 0.0f},
         {TEXT("0.05 / 0.7"),  0.05f, 0.7f, 0.0f, 0.0714f},

         //Zero dividend
         {TEXT("0 / 5"),  0.0f, 5.0f, 0.0f, 0.0f},
         {TEXT("0 / -5"),  0.0f, -5.0f, 0.0f, 0.0f},
         {TEXT("0 / 0.05"),  0.0f, 0.05f, 0.0f, 0.0f},

         //Division by zero
         {TEXT("5 / 0"),  5.0f, 0.0f, 0.0f, 0.0f},
         {TEXT("-5 / 0"),  -5.0f, 0.0f, 0.0f, 0.0f},
         {TEXT("0 / 0"),  0.0f, 0.0f, 0.0f, 0.0f},

         //Negative remainders with small quotients
         {TEXT("-0.3 / 0.1"),  -0.3f, 0.1f, -3.0f, 0.0f},
         {TEXT("-0.3 / 0.2"),  -0.3f, 0.2f, -1.0f, -0.5f},
         {TEXT("-0.1 / 0.3"),  -0.1f, 0.3f, 0.0f, -0.3333f},

         //Close to whole number
         {TEXT("1.9999 / 1.0"),  1.9999f, 1.0f, 1.0f, 0.9999f},
         {TEXT("-1.9999 / 1.0"),  -1.9999f, 1.0f, -1.0f, -0.9999f},

         //Perfectly divisible
         {TEXT("10 / 2"),  10.0f, 2.0f, 5.0f, 0.0f},
         {TEXT("-10 / 2"),  -10.0f, 2.0f, -5.0f, 0.0f},
         {TEXT("10 / -2"),  10.0f, -2.0f, -5.0f, 0.0f},

         //Fractional divisors
         {TEXT("4.5 / 0.5"),  4.5f, 0.5f, 9.0f, 0.0f},
         {TEXT("7.25 / 0.25"),  7.25f, 0.25f, 29.0f, 0.0f},
         {TEXT("-3.75 / 0.25"),  -3.75f, 0.25f, -15.0f, 0.0f},

         //Very small and large values
         {TEXT("1e-6 / 1.0"),  1e-6f, 1.0f, 0.0f, 1e-6f},
         {TEXT("1e6 / 2"),  1000000.0f, 2.0f, 500000.0f, 0.0f},
         {TEXT("1e6 / 3"),  1000000.0f, 3.0f, 333333.0f, 0.333333f},

         //Arbitrary remainder checks
         {TEXT("1 / 3"),  1.0f, 3.0f, 0.0f, 0.3333f},
         {TEXT("1 / 7"),  1.0f, 7.0f, 0.0f, 0.142857f},
         {TEXT("0.3 / 0.1"),  0.3f, 0.1f, 3.0f, 0.0f}
      };

      UE_LOG(MathExtensions, Warning, TEXT("Starting Division tests."));

      for (const auto& test : cases) {
         float calculatedWhole = -999.0f;
         float calculatedRem = -999.0f;

         //The function being tested
         Division(test.dividend, test.divisor, calculatedWhole, calculatedRem);

         bool wholeResult = std::abs(calculatedWhole - test.expectedWhole) < EPSILON;
         bool remResult = std::abs(calculatedRem - test.expectedRem) < EPSILON;

         if (!wholeResult || !remResult) {
            FString message = FString::Printf(
               TEXT("Calculation mismatch! Expected: %s -> Whole: %f Rem: %f"), 
               *test.description, calculatedWhole, calculatedRem);

            UE_LOG(MathExtensions, Warning, TEXT("%s"), *message);
         }
      }

      UE_LOG(MathExtensions, Warning, TEXT("All Division tests finished."));
   }
};

Its essentially a floating point issue.
The engine became “full on retarded” since they decided to change from float (as you just detailed).

Currently, your best solution is to not use Kismeth for anything that you need accurate results on - at least as a noob incapable of even looking at what you already looked at.

For you.
I’d suggest pulling a git version of the engine and just fixing the code - you are bascially there.
The math is incorrect - I’d wager you need to round up, not down.

To just quote the c++ docs for ya:

The IEEE floating-point remainder of the division operation x / y calculated by this function is exactly the value x - quo * y, where the value quo is the integral value nearest the exact value x / y. When |quo - x / y| = ½, the value quo is chosen to be even.

Honestly, just override the engine trash with the proper function you already looked at… I doubt there is any reason for Epic to be touching proper math with their own interpretations like you see in the Kismeth stuff…
We are on the 2+2 = 22 level (and if you dont know what that means, have a google search).

And here I was hoping I was missing something being ‘new-ish’ to UE…

I’m in a tiny programmer team of 1 (2 if we can fill the open position) so I’d prefer to avoid maintaining and fixing my own branch of the engine. We do implement using a 60-40 mix of C++ and BP’s, but I’ll keep in mind your recommendation to avoid BP’s for math as much as possible.

I’m in the camp of 2 + 2 == 4, "2" + "2" == "22", and '2' + '2' == ▬

If you are working on a project you want to release you need to pick a git version of the engine, test for viability, and never update it again if not to bugfix by cherripicking whatever the git may have shared that is new.

Save yourself from future problems :wink:

After being bothered with my first fix I’ve put together the following that takes advantage of double precision and the C++ std static_cast to as far as I can tell negate the floating point precision issue. Critically, for my use at least, it works as one would expect if they intended for a decimal remainder. (Although one can argue floor vs ceil with negative numbers.)

Additionally, 5.0f / 2.0f = 2.5f can be interpreted as {2.0f, 0.5f} or "2 remainder 1" depending on use case. When needing the former one can use the remainder as-is, for the latter they should multiply the remainder by the divisor.

#pragma once
#include "CoreMinimal.h"

#define EPSILON 0.0001f

UCLASS(meta = (BlueprintThreadSafe))
class VR_BASE_API UMathBPFL : public UBlueprintFunctionLibrary {
	GENERATED_BODY()

public:
	/// <summary>Returns the number of times the divisor goes into the dividend along with the remainder as a fraction of the dividend.
	/// For remainder as a whole number, multiply it by the divisor. 
	/// EG: 5/2 = 2.5f can be interpreted as {2.0f, 0.5f} or "2 remainder 1".</summary>
	static void DivisionFractionalRem(float dividend, float divisor, float& outWhole, float& outFractional) {
		if (divisor != 0.0f) {
		  const double divident_d = static_cast<double>(dividend);
		  const double divisor_d = static_cast<double>(divisor);
		  const double quotient = divident_d / divisor_d;
		  
		  //Takes advantage of how doubles are cast back to floats to negate the inaccuracies in floats for small numbers
		  const float accurateQuotient = static_cast<float>(quotient);
		  if (accurateQuotient >= 0.0f) {
			 outWhole = std::floor(accurateQuotient);
		  } else {
			 outWhole = std::ceil(accurateQuotient);
		  }

		  //Remainder as a fraction
		  outFractional = static_cast<float>((divident_d - (outWhole * divisor_d)) / divisor_d);

		} else {
			UE_LOG(MathExtensions, Warning, TEXT("Attempted to divide by zero - Returning 0 instead of collapsing the universe."));
			outWhole = 0.0f;
		  outFractional = 0.0f;
		}
	}
};

The below contains the function i used to test this. let me know if anyone sees a missing test case.

The Test
 static void TestDivisionFractionalRem() {
    struct TestCase {
       const FString description;
       float dividend;
       float divisor;
       float expectedWhole;
       float expectedRem;
    };

    TestCase cases[] = {
       //Standard cases
       {TEXT("5 / 2"), 5.0f, 2.0f, 2.0f, 0.5f},
       {TEXT("2 / 5"),  2.0f, 5.0f, 0.0f, 0.4f},
       {TEXT("-5 / 2"),  -5.0f, 2.0f, -2.0f, -0.5f},
       {TEXT("-2 / 5"),  -2.0f, 5.0f, 0.0f, -0.4f},
       {TEXT("-5 / -2"),  -5.0f, -2.0f, 2.0f, 0.5f},
       {TEXT("-2 / -5"),  -2.0f, -5.0f, 0.0f, 0.4f},
       {TEXT("0.7 / 0.05"),  0.7f, 0.05f, 14.0f, 0.0f},
       {TEXT("0.05 / 0.7"),  0.05f, 0.7f, 0.0f, 0.0714f},

       //Zero dividend
       {TEXT("0 / 5"),  0.0f, 5.0f, 0.0f, 0.0f},
       {TEXT("0 / -5"),  0.0f, -5.0f, 0.0f, 0.0f},
       {TEXT("0 / 0.05"),  0.0f, 0.05f, 0.0f, 0.0f},

       //Division by zero
       {TEXT("5 / 0"),  5.0f, 0.0f, 0.0f, 0.0f},
       {TEXT("-5 / 0"),  -5.0f, 0.0f, 0.0f, 0.0f},
       {TEXT("0 / 0"),  0.0f, 0.0f, 0.0f, 0.0f},

       //Negative remainders with small quotients
       {TEXT("-0.3 / 0.1"),  -0.3f, 0.1f, -3.0f, 0.0f},
       {TEXT("-0.3 / 0.2"),  -0.3f, 0.2f, -1.0f, -0.5f},
       {TEXT("-0.1 / 0.3"),  -0.1f, 0.3f, 0.0f, -0.3333f},

       //Close to whole number
       {TEXT("1.9999 / 1.0"),  1.9999f, 1.0f, 1.0f, 0.9999f},
       {TEXT("-1.9999 / 1.0"),  -1.9999f, 1.0f, -1.0f, -0.9999f},

       //Perfectly divisible
       {TEXT("10 / 2"),  10.0f, 2.0f, 5.0f, 0.0f},
       {TEXT("-10 / 2"),  -10.0f, 2.0f, -5.0f, 0.0f},
       {TEXT("10 / -2"),  10.0f, -2.0f, -5.0f, 0.0f},

       //Fractional divisors
       {TEXT("4.5 / 0.5"),  4.5f, 0.5f, 9.0f, 0.0f},
       {TEXT("7.25 / 0.25"),  7.25f, 0.25f, 29.0f, 0.0f},
       {TEXT("-3.75 / 0.25"),  -3.75f, 0.25f, -15.0f, 0.0f},

       //Very small and large values
       {TEXT("1e-6 / 1.0"),  1e-6f, 1.0f, 0.0f, 1e-6f},
       {TEXT("1e6 / 2"),  1000000.0f, 2.0f, 500000.0f, 0.0f},
       {TEXT("1e6 / 3"),  1000000.0f, 3.0f, 333333.0f, 0.333333f},

       //Arbitrary remainder checks
       {TEXT("1 / 3"),  1.0f, 3.0f, 0.0f, 0.3333f},
       {TEXT("1 / 7"),  1.0f, 7.0f, 0.0f, 0.142857f},
       {TEXT("0.3 / 0.1"),  0.3f, 0.1f, 3.0f, 0.0f}
    };

    UE_LOG(MathExtensions, Warning, TEXT("Starting Division (Fractional) tests."));

    for (const auto& test : cases) {
       float calculatedWhole = -999.0f;
       float calculatedRem = -999.0f;

       //Where the remainder is a decimal
       DivisionFractionalRem(test.dividend, test.divisor, calculatedWhole, calculatedRem);

       bool wholeResult = std::abs(calculatedWhole - test.expectedWhole) > EPSILON;
       bool remResult = std::abs(calculatedRem - test.expectedRem) > EPSILON;

       if (wholeResult || remResult) {
          FString message = FString::Printf(
             TEXT("Calculation mismatch! Expected: %s -> Whole: %f Rem: %f"), 
             *test.description, calculatedWhole, calculatedRem);

          UE_LOG(MathExtensions, Warning, TEXT("%s"), *message);
       }
    }

    UE_LOG(MathExtensions, Warning, TEXT("Division tests finished."));
 }