FMath::FMod

I’m using FMod to check whether a float is even or odd, but it says 2.000 % 2 = 2.
Here’s the function:

FIntPoint AGrid::GetHexagonIndex(FVector gridlocation)
{
	FVector2d SnappedGridLocation(UUtilitiesLibrary::SnapVectorToVector(gridlocation * FVector{1,2,1}, _TileSize * FVector{ 0.75, 0.25 , 1 }));
	FVector2d TempIndex(SnappedGridLocation / (FVector2d(_TileSize) * FVector2D{0.75, 1}));

	UE_LOG(LogTemp, Display, TEXT("TempIndex %f : %f"), TempIndex.X, TempIndex.Y);
	UE_LOG(LogTemp, Display, TEXT("FMath::Fmod(TempIndex.X, 2) = %f"), FMath::Fmod(TempIndex.X, 2));

	if (FMath::Fmod(TempIndex.X, 2) == 0)
	{
		FIntPoint Index = FIntPoint(FMath::TruncToInt(TempIndex.X), FMath::TruncToInt(FMath::RoundToFloat(TempIndex.Y / 2) * 2));
		return Index;
	}
	else
	{
		FIntPoint Index = FIntPoint(FMath::TruncToInt(TempIndex.X), FMath::TruncToInt(FMath::Floor(TempIndex.Y / 2) * 2 ) +1);
		return Index;
	}

	return FIntPoint(-999, -999);
}

And here’s the log:
image

I tried checking the documentation, but found nothing. Can anyone explain why is this happening?

The modulus of a number is the same number but always positive.

Module 3.2 = 3.2
Module -3.2 = 3.2

This might be happening because of float precision.
Basically: 2, 2.0 and 2.0f are not entirely the same and they can differ.
Could you check if 2.000 % 2.000 or 2.000 % 2.000f give the same result?
Also, are you sure that TempIndex.X is an actual float? not double?
There might be an implicit cast happening somewhere. This could mess the result.


This is not true (?) or I might be missing something.

Python 3.12.6 (main, Sep  8 2024, 13:18:56) [GCC 14.2.1 20240805] on linux
>>> 2.000 % 2
0.0
1 Like

I was wrong (got the concepts mixed up). The mod in this case should return the remainder of the division.
FMath::Fmod does different things depending on the platform, and apparently it really doesn’t work quite correctly…

It seems better to just use A % B. The Blueprint function does exactly that, after all.

The code is the same as before, with a couple more uelog

FIntPoint AGrid::GetHexagonIndex(FVector gridlocation)
{
	FVector2d SnappedGridLocation(UUtilitiesLibrary::SnapVectorToVector(gridlocation * FVector{1,2,1}, _TileSize * FVector{ 0.75, 0.25 , 1 }));
	FVector2d TempIndex(SnappedGridLocation / (FVector2d(_TileSize) * FVector2D{0.75, 1}));

	UE_LOG(LogTemp, Display, TEXT("TempIndex %f : %f"), TempIndex.X, TempIndex.Y);
	UE_LOG(LogTemp, Display, TEXT("FMath::Fmod(TempIndex.X, 2) = %f"), FMath::Fmod(TempIndex.X, 2.000));
	UE_LOG(LogTemp, Display, TEXT("2.000 mod 2.000 = %d"), FMath::Fmod(2.000 , 2.000));
	UE_LOG(LogTemp, Display, TEXT("2.000 mod 2.000f = %d"), FMath::Fmod(2.000, 2.000f));
	UE_LOG(LogTemp, Display, TEXT("2.000 mod 2 = %i"), FMath::Fmod(2.000, 2));

	if (FMath::Fmod(TempIndex.X, 2) == 0)
	{
		FIntPoint Index = FIntPoint(FMath::TruncToInt(TempIndex.X), FMath::TruncToInt(FMath::RoundToFloat(TempIndex.Y / 2) * 2));
		return Index;
	}
	else
	{
		FIntPoint Index = FIntPoint(FMath::TruncToInt(TempIndex.X), FMath::TruncToInt(FMath::Floor(TempIndex.Y / 2) * 2 ) +1);
		return Index;
	}

	return FIntPoint(-999, -999);
}

TempIndex x and y are both double

and fmod function have an overload for (double, int)

When tempindex is 6 the result is correct though

I also added the double,int overload after that
(Sorry about this ugly collage, but new users can upload 1 image only)

I also tried using 2.000 and 2.000f in the if statement, but nothing changed.

Odd/even does not apply to floating point numbers.
Is 101.8 even? Is 92.3 odd? There is no way to tell.

If you are not interested in the fractional part, use casting and modulo

if (static_cast<int>(YourFloat) % 2 == 0) {
   // even
}