Floating point precision

Hello,

I have a CPP project and a ue4 CPP project

I’m doing a bunch of calculations and when i call


sin(4141414414141414.0f)

I get a different value from each

UE4 - SIN: 0.899859
CPP - SIN: 0.899861

Probably a daft question I’m just wondering why?
They are both using math.h from what I can see they are both running on the same machine.

I’m not very good with CPP so I’m just wondering if someone can tell me why this might be happening and if its possible to make the two match?

Thanks a lot in advance.

FMath::Sin uses sinf, not sin. In UE4 Are you calling FMath::Sin or just sin?

Hi, thanks for the response,

I’m using just sin,

When I click on the method sin in both projects it opens up cmath which then uses sinf()
However when I click on that methods the UE4 project opens up math.h and the CPP project opens up correct_math.h

Not sure if any of that helps.

Further investigation I have found a “magic number”

929887887991829

If anything large than that number is added to the sin function it starts to give out different numbers the native CPP project

this sin(929887887991829) in both projects produce

UE4 - SIN: 0.958895
CPP - SIN: 0.958895

However

sin(929887887991830)

produces the following

UE4 - SIN: 0.322073
CPP - SIN: 0.322072

I assume there is some limit or rounding or something on UE4?

Shouldn’t you be using doubles for numbers that obviously can’t be accurately represented by a single precision float?

Sorry, I don’t understand what you mean.

seedCalc is a double



float X = 2450;
float Y = 2440;
float Z = -30;

double a = (pow(10, 9) + pow(10, 5) + 10);
double seedCalc = 5 * a + X * pow(10, 6) + Y * pow(10, 2) + Z;



seedCalc give out

7450744010.000000 UE4

7450744020.000000 CPP

Ok, in your first post you had an ‘f’ suffix for the number so I assumed you’re using floats.
Also I don’t see ‘sin’ anywhere so it’s obviously not related to that.
Could be that you are compiling with different floating point precision options than UE4 is.

See https://docs.microsoft.com/en-us/cpp…r?view=vs-2019

From UE4 Build tool source:


if (Target.WindowsPlatform.Compiler == WindowsCompiler.Intel || Target.WindowsPlatform.Compiler == WindowsCompiler.Clang)
{
// FMath::Sqrt calls get inlined and when reciprical is taken, turned into an rsqrtss instruction,
// which is *too* imprecise for, e.g., TestVectorNormalize_Sqrt in UnrealMathTest.cpp
// TODO: Observed in clang 7.0, presumably the same in Intel C++ Compiler?
Arguments.Add("/fp:precise");
}
else
{
// Relaxes floating point precision semantics to allow more optimization.
Arguments.Add("/fp:fast");
}

Sorry, this is one of many different function im using and many of these math functions sin cos pow thery all produce different results in UE4 than CPP.

Which /fp flag are you building your c++ program with?

Morning,


Precise(/fp:precise)

It is definitely something to do with large numbers being passed into sin everything is the same until I pass Val into the sin function, then all hell breaks loose

UE4
X: 2450.000000, Y: 2440.000000, Z: -40.000000, pow(10, 6) = 1000000.000000, pow(10, 2) = 100.000000
Density: 0.157030
Star amount: 12 GG: 7450744010.000000 A: 1000100010.000000
Val: 100000007450744016.000000
ValSin: 0.393407
ValFloor: 3934.000000
StellaCharacteristicsSeed: 0.074625

CPP
X: 2450.000000, Y: 2440.000000, Z: -40.000000, pow(10, 6) = 1000000.000000, pow(10, 2) = 100.000000
Density: 0.157030
Star amount: 12 GG: 7450744010.000000 A: 1000100010.000000
Val: 100000007450744016.000000
ValSin: 0.393289
ValFloor: 3932.000000
StellaCharacteristicsSeed: 0.890989


double a = (pow(10, 9) + pow(10, 5) + 10);
double gg = 5 * a + X * pow(10, 6) + Y * pow(10, 2) + Z;

Seed *seed = new Seed(gg, false);

int StarAmount = (int)round(78 * Density * (1 + 2.2 * (pow(seed->GetValue() - 0.5, 3))));

double Val = gg + pow(10, 17);

for (auto i = 1; i < StarAmount; i++) {
    FStar* Star = new FStar();
    Seed *StellaCharacteristicsSeed = new Seed(t * i, true);
    double s = StellaCharacteristicsSeed->GetValue();

    UE_LOG(LogTemp, Warning, TEXT("StellaCharacteristicsSeed: %f 
"), s);
}





Seed::Seed(double value, bool debug)
{
    this->value = value;
    this->debug = debug;
}

float Seed::GetValue() {
    if (debug) {
        UE_LOG(LogTemp, Warning, TEXT("Val: %f"), this->value);
        UE_LOG(LogTemp, Warning, TEXT("ValSin: %f"), sin(this->value));
        UE_LOG(LogTemp, Warning, TEXT("ValFloor: %f"), floor(sin(this->value) * 10000));
    }
    this->value = sin(this->value) * 10000;
    return this->value - floor(this->value);
}


Try /fp:fast

Same issue when I switched.

I have moved on further now, I have lowered the values so they fall within the allowed scope this has resulted in the correct behaviour between both applications

With the exception of the log function


double AGalaxy::radius(double StellaCharacteristicsSeed) {
    double rad = min(0.08 - 0.43912 * log(1 - StellaCharacteristicsSeed), 12.0);
    return rad;
}

Star ID 2b2c144ecb05ee720af871bb2af50822.
Star lum: 0.121248
StellaCharacteristicsSeed: 0.785080
log(1 - StellaCharacteristicsSeed)=: -1.537487
Star rad: 0.755141


double radius(double stellaCharacteristicsSeed) {
    double rad = min(0.08 - 0.43912 * log(1 - stellaCharacteristicsSeed), 12.0);
    return rad;
}


Star ID: 2b2c144ecb05ee720af871bb2af50822
Star lum: 0.121248
StellaCharacteristicsSeed: 0.785080
log(1 - stellaCharacteristicsSeed)=: -1.537488
Star rad: 0.755142