Skip to content

Floating point computation changed in windows 24H2

Summary

After upgrade to windows 24H2 we saw an inconsistency in our test results between our local development machine and our continuous integration machine. Results produced by both machine differs and are way beyond +-1ULP.

Environment

  • Operating System : Windows
  • Architecture : x64
  • Eigen Version : 3.4.0
  • Compiler Version : MSVC 2019 (19.29.30157.0), toolset v142
  • Compile Flags : /fp:strict /fp:except /permissive- /MP2 /EHsc /O2 /std:c++20 /DWIN32 /D_WINDOWS
  • Vector Extension : AFAIK SSE2 (nothing done on our side to manage this one).

Minimal Example

#include <gtest/gtest.h>
#include <iostream>
#include <iomanip>
#include <limits>
#include <Eigen/Core>


TEST(PointCloudUtilsTests, matrixMultiplication_equalExpected)
    {
        // store default env;
        unsigned int originalControlWord = 0;
        _controlfp_s(&originalControlWord, 0, 0);
        // fixing fp control
        unsigned int fpControlMask =  FE_DIVBYZERO | FE_INVALID | FE_OVERFLOW | FE_UNDERFLOW | RC_NEAR;
        _controlfp_s(nullptr, ~fpControlMask, fpControl
Mask);

        auto loadPointFromFile = [](const std::filesystem::path& p_path) -> std::vector<Eigen::Vector3d>
		{
			std::vector<Eigen::Vector3d> points;
			std::ifstream file(p_path.string());
			double x, y, z = 0;
			while (file >> x >> y >> z)
			{
				points.emplace_back(x, y, z);
			}

			return points;
		};

		auto toMatrix = [](const std::vector<Eigen::Vector3d>& p_pointCloud) {
			Eigen::MatrixX3d points(p_pointCloud.size(), 3);
			std::cout << "Set of 3d points : " << std::endl;
			for (int i = 0; i < p_pointCloud.size(); ++i)
			{
				Eigen::IOFormat fullPrecisionFmt(Eigen::FullPrecision);
				std::cout << std::fixed << std::setprecision(std::numeric_limits<double>::max_digits10) << p_pointCloud[i].x() <<  " " << p_pointCloud[i].y() <<  " " << p_pointCloud[i].z() << std::endl;
				points.row(i) = p_pointCloud[i];
			}
			return points;
		};

		const auto pointcloudFilePath = std::filesystem::path(__argv[0]).parent_path() / "pointcloud.txt";
		ASSERT_TRUE(std::filesystem::exists(pointcloudFilePath));

		const std::vector<Eigen::Vector3d> points = loadPointFromFile(pointcloudFilePath);
		ASSERT_FALSE(points.empty());

        const Eigen::MatrixX3d matrix = toMatrix(points);
        const Eigen::Matrix3d covariance = matrix.transpose() * matrix;

        Eigen::IOFormat fullPrecisionFmt(Eigen::FullPrecision);
        std::cout << "Covariance matrix : " << std::endl;
        std::cout << std::fixed << covariance.format(fullPrecisionFmt) << std::endl;

        EXPECT_EQ(covariance.row(0), Eigen::Vector3d(37015361.39861094951629639, 65914992.65099146962165833, 504969830.10096740722656250).transpose());
        EXPECT_EQ(covariance.row(1), Eigen::Vector3d(65914992.65099146962165833, 135128697.05431032180786133, 1018944393.48469054698944092).transpose());
        EXPECT_EQ(covariance.row(2), Eigen::Vector3d(504969830.10096740722656250, 1018944393.48469054698944092, 7853173472.83890151977539062).transpose());

        // restore
        _controlfp_s(nullptr, originalControlWord, 0xFFFFFFFF);
    }

Note that gtest is totally optional.

Steps to reproduce

  1. Compile the code
  2. Download pointcloud.txt and put next to the binary
  3. Run the binary on windows version at least equal to 24H2
  4. Test shall pass
  5. Run the binary on windows version lower than 23H2
  6. Test shall fail

What is the current bug behavior?

Results comming from the same binary are different depending the windows version

What is the expected correct behavior?

Same Results

Relevant logs

Anything else that might help

I'm unsure this bug come from libeigen but thought that you may have a clue about what's happening here. I also created a post on MS forums here while I was investigating this bug.

  • We checked that it was not related to P/E cores.