diff --git a/modules/core/src/persistence.cpp b/modules/core/src/persistence.cpp index 5f7f638397..a9a2eb5db0 100644 --- a/modules/core/src/persistence.cpp +++ b/modules/core/src/persistence.cpp @@ -76,9 +76,11 @@ char* doubleToString( char* buf, size_t bufSize, double value, bool explicitZero } else { - static const char* fmt = "%.16e"; + // binary64 has 52 bit fraction with hidden bit. + // 53 * log_10(2) is 15.955. So "%.16f" should be fine, but its test fails. + snprintf( buf, bufSize, "%.17g", value ); + char* ptr = buf; - snprintf( buf, bufSize, fmt, value ); if( *ptr == '+' || *ptr == '-' ) ptr++; for( ; cv_isdigit(*ptr); ptr++ ) @@ -118,11 +120,21 @@ char* floatToString( char* buf, size_t bufSize, float value, bool halfprecision, } else { - char* ptr = buf; if (halfprecision) - snprintf(buf, bufSize, "%.4e", value); + { + // bfloat16 has 7 bit fraction with hidden bit. + // binary16 has 10 bit fraction with hidden bit. + // 11 * log_10(2) is 3.311. So "%.4f" should be fine, but its test fails. + snprintf(buf, bufSize, "%.5g", value); + } else - snprintf(buf, bufSize, "%.8e", value); + { + // binray32 has 23 bit fraction with hidden bit. + // 24 * log_10(2) is 7.225. So "%.8f" should be fine, but its test fails. + snprintf(buf, bufSize, "%.9g", value); + } + + char* ptr = buf; if( *ptr == '+' || *ptr == '-' ) ptr++; for( ; cv_isdigit(*ptr); ptr++ ) diff --git a/modules/core/test/test_io.cpp b/modules/core/test/test_io.cpp index ce287af922..f0f0645bcf 100644 --- a/modules/core/test/test_io.cpp +++ b/modules/core/test/test_io.cpp @@ -1189,11 +1189,7 @@ TEST(Core_InputOutput, FileStorage_DMatch) EXPECT_NO_THROW(fs << "d" << d); cv::String fs_result = fs.releaseAndGetString(); -#if defined _MSC_VER && _MSC_VER <= 1800 /* MSVC 2013 and older */ - EXPECT_STREQ(fs_result.c_str(), "%YAML:1.0\n---\nd: [ 1, 2, 3, -1.5000000000000000e+000 ]\n"); -#else - EXPECT_STREQ(fs_result.c_str(), "%YAML:1.0\n---\nd: [ 1, 2, 3, -1.5000000000000000e+00 ]\n"); -#endif + EXPECT_STREQ(fs_result.c_str(), "%YAML:1.0\n---\nd: [ 1, 2, 3, -1.5 ]\n"); cv::FileStorage fs_read(fs_result, cv::FileStorage::READ | cv::FileStorage::MEMORY); @@ -1220,25 +1216,14 @@ TEST(Core_InputOutput, FileStorage_DMatch_vector) EXPECT_NO_THROW(fs << "dv" << dv); cv::String fs_result = fs.releaseAndGetString(); -#if defined _MSC_VER && _MSC_VER <= 1800 /* MSVC 2013 and older */ EXPECT_STREQ(fs_result.c_str(), "%YAML:1.0\n" "---\n" "dv:\n" -" - [ 1, 2, 3, -1.5000000000000000e+000 ]\n" -" - [ 2, 3, 4, 1.5000000000000000e+000 ]\n" -" - [ 3, 2, 1, 5.0000000000000000e-001 ]\n" +" - [ 1, 2, 3, -1.5 ]\n" +" - [ 2, 3, 4, 1.5 ]\n" +" - [ 3, 2, 1, 0.5 ]\n" ); -#else - EXPECT_STREQ(fs_result.c_str(), -"%YAML:1.0\n" -"---\n" -"dv:\n" -" - [ 1, 2, 3, -1.5000000000000000e+00 ]\n" -" - [ 2, 3, 4, 1.5000000000000000e+00 ]\n" -" - [ 3, 2, 1, 5.0000000000000000e-01 ]\n" -); -#endif cv::FileStorage fs_read(fs_result, cv::FileStorage::READ | cv::FileStorage::MEMORY); @@ -1278,33 +1263,18 @@ TEST(Core_InputOutput, FileStorage_DMatch_vector_vector) EXPECT_NO_THROW(fs << "dvv" << dvv); cv::String fs_result = fs.releaseAndGetString(); #ifndef OPENCV_TRAITS_ENABLE_DEPRECATED -#if defined _MSC_VER && _MSC_VER <= 1800 /* MSVC 2013 and older */ EXPECT_STREQ(fs_result.c_str(), "%YAML:1.0\n" "---\n" "dvv:\n" " -\n" -" - [ 1, 2, 3, -1.5000000000000000e+000 ]\n" -" - [ 2, 3, 4, 1.5000000000000000e+000 ]\n" -" - [ 3, 2, 1, 5.0000000000000000e-001 ]\n" +" - [ 1, 2, 3, -1.5 ]\n" +" - [ 2, 3, 4, 1.5 ]\n" +" - [ 3, 2, 1, 0.5 ]\n" " -\n" -" - [ 3, 2, 1, 5.0000000000000000e-001 ]\n" -" - [ 1, 2, 3, -1.5000000000000000e+000 ]\n" +" - [ 3, 2, 1, 0.5 ]\n" +" - [ 1, 2, 3, -1.5 ]\n" ); -#else - EXPECT_STREQ(fs_result.c_str(), -"%YAML:1.0\n" -"---\n" -"dvv:\n" -" -\n" -" - [ 1, 2, 3, -1.5000000000000000e+00 ]\n" -" - [ 2, 3, 4, 1.5000000000000000e+00 ]\n" -" - [ 3, 2, 1, 5.0000000000000000e-01 ]\n" -" -\n" -" - [ 3, 2, 1, 5.0000000000000000e-01 ]\n" -" - [ 1, 2, 3, -1.5000000000000000e+00 ]\n" -); -#endif #endif // OPENCV_TRAITS_ENABLE_DEPRECATED cv::FileStorage fs_read(fs_result, cv::FileStorage::READ | cv::FileStorage::MEMORY); @@ -1966,5 +1936,53 @@ TEST(Core_InputOutput, FileStorage_invalid_path_regression_21448_JSON) fs.release(); } +// see https://github.com/opencv/opencv/issues/25073 +typedef testing::TestWithParam< std::string > Core_InputOutput_regression_25073; + +TEST_P(Core_InputOutput_regression_25073, my_double) +{ + cv::String res = ""; + double my_double = 0.5; + + FileStorage fs( GetParam(), cv::FileStorage::WRITE | cv::FileStorage::MEMORY); + EXPECT_NO_THROW( fs << "my_double" << my_double ); + EXPECT_NO_THROW( fs << "my_int" << 5 ); + EXPECT_NO_THROW( res = fs.releaseAndGetString() ); + EXPECT_NE( res.find("0.5"), String::npos ) << res; // Found "0.5" + EXPECT_EQ( res.find("5.0"), String::npos ) << res; // Not Found "5.000000000000000000e-01" + fs.release(); +} + +TEST_P(Core_InputOutput_regression_25073, my_float) +{ + cv::String res = ""; + float my_float = 0.5; + + FileStorage fs( GetParam(), cv::FileStorage::WRITE | cv::FileStorage::MEMORY); + EXPECT_NO_THROW( fs << "my_float" << my_float ); + EXPECT_NO_THROW( fs << "my_int" << 5 ); + EXPECT_NO_THROW( res = fs.releaseAndGetString() ); + EXPECT_NE( res.find("0.5"), String::npos ) << res; // Found "0.5" + EXPECT_EQ( res.find("5.0"), String::npos ) << res; // Not Found "5.00000000e-01", + fs.release(); +} + +TEST_P(Core_InputOutput_regression_25073, my_float16) +{ + cv::String res = ""; + cv::float16_t my_float16(0.5); + + FileStorage fs( GetParam(), cv::FileStorage::WRITE | cv::FileStorage::MEMORY); + EXPECT_NO_THROW( fs << "my_float16" << my_float16 ); + EXPECT_NO_THROW( fs << "my_int" << 5 ); + EXPECT_NO_THROW( res = fs.releaseAndGetString() ); + EXPECT_NE( res.find("0.5"), String::npos ) << res; // Found "0.5". + EXPECT_EQ( res.find("5.0"), String::npos ) << res; // Not Found "5.0000e-01". + fs.release(); +} + +INSTANTIATE_TEST_CASE_P( /*nothing*/, + Core_InputOutput_regression_25073, + Values("test.json", "test.xml", "test.yml") ); }} // namespace diff --git a/modules/features2d/misc/java/test/AKAZEDescriptorExtractorTest.java b/modules/features2d/misc/java/test/AKAZEDescriptorExtractorTest.java index 69b12d00b1..a64b6ae4ad 100644 --- a/modules/features2d/misc/java/test/AKAZEDescriptorExtractorTest.java +++ b/modules/features2d/misc/java/test/AKAZEDescriptorExtractorTest.java @@ -58,7 +58,7 @@ public class AKAZEDescriptorExtractorTest extends OpenCVTestCase { extractor.write(filename); - String truth = "%YAML:1.0\n---\nformat: 3\nname: \"Feature2D.AKAZE\"\ndescriptor: 5\ndescriptor_channels: 3\ndescriptor_size: 0\nthreshold: 1.0000000474974513e-03\noctaves: 4\nsublevels: 4\ndiffusivity: 1\nmax_points: -1\n"; + String truth = "%YAML:1.0\n---\nformat: 3\nname: \"Feature2D.AKAZE\"\ndescriptor: 5\ndescriptor_channels: 3\ndescriptor_size: 0\nthreshold: 0.0010000000474974513\noctaves: 4\nsublevels: 4\ndiffusivity: 1\nmax_points: -1\n"; String actual = readFile(filename); actual = actual.replaceAll("e([+-])0(\\d\\d)", "e$1$2"); // NOTE: workaround for different platforms double representation assertEquals(truth, actual); diff --git a/modules/features2d/misc/java/test/GFTTFeatureDetectorTest.java b/modules/features2d/misc/java/test/GFTTFeatureDetectorTest.java index 86e42cbc1d..d21d4f2475 100644 --- a/modules/features2d/misc/java/test/GFTTFeatureDetectorTest.java +++ b/modules/features2d/misc/java/test/GFTTFeatureDetectorTest.java @@ -58,7 +58,7 @@ public class GFTTFeatureDetectorTest extends OpenCVTestCase { detector.write(filename); - String truth = "%YAML:1.0\n---\nname: \"Feature2D.GFTTDetector\"\nnfeatures: 1000\nqualityLevel: 1.0000000000000000e-02\nminDistance: 1.\nblockSize: 3\ngradSize: 3\nuseHarrisDetector: 0\nk: 4.0000000000000001e-02\n"; + String truth = "%YAML:1.0\n---\nname: \"Feature2D.GFTTDetector\"\nnfeatures: 1000\nqualityLevel: 0.01\nminDistance: 1.\nblockSize: 3\ngradSize: 3\nuseHarrisDetector: 0\nk: 0.040000000000000001\n"; String actual = readFile(filename); actual = actual.replaceAll("e([+-])0(\\d\\d)", "e$1$2"); // NOTE: workaround for different platforms double representation assertEquals(truth, actual); diff --git a/modules/features2d/misc/java/test/KAZEDescriptorExtractorTest.java b/modules/features2d/misc/java/test/KAZEDescriptorExtractorTest.java index 69ca35e015..d33ee24f49 100644 --- a/modules/features2d/misc/java/test/KAZEDescriptorExtractorTest.java +++ b/modules/features2d/misc/java/test/KAZEDescriptorExtractorTest.java @@ -57,7 +57,7 @@ public class KAZEDescriptorExtractorTest extends OpenCVTestCase { extractor.write(filename); - String truth = "%YAML:1.0\n---\nformat: 3\nname: \"Feature2D.KAZE\"\nextended: 0\nupright: 0\nthreshold: 1.0000000474974513e-03\noctaves: 4\nsublevels: 4\ndiffusivity: 1\n"; + String truth = "%YAML:1.0\n---\nformat: 3\nname: \"Feature2D.KAZE\"\nextended: 0\nupright: 0\nthreshold: 0.0010000000474974513\noctaves: 4\nsublevels: 4\ndiffusivity: 1\n"; String actual = readFile(filename); actual = actual.replaceAll("e([+-])0(\\d\\d)", "e$1$2"); // NOTE: workaround for different platforms double representation assertEquals(truth, actual); diff --git a/modules/features2d/misc/java/test/MSERFeatureDetectorTest.java b/modules/features2d/misc/java/test/MSERFeatureDetectorTest.java index 7f5f1c1849..956e0600e3 100644 --- a/modules/features2d/misc/java/test/MSERFeatureDetectorTest.java +++ b/modules/features2d/misc/java/test/MSERFeatureDetectorTest.java @@ -61,7 +61,7 @@ public class MSERFeatureDetectorTest extends OpenCVTestCase { detector.write(filename); - String truth = "%YAML:1.0\n---\nname: \"Feature2D.MSER\"\ndelta: 5\nminArea: 60\nmaxArea: 14400\nmaxVariation: 2.5000000000000000e-01\nminDiversity: 2.0000000000000001e-01\nmaxEvolution: 200\nareaThreshold: 1.0100000000000000e+00\nminMargin: 3.0000000000000001e-03\nedgeBlurSize: 5\npass2Only: 0\n"; + String truth = "%YAML:1.0\n---\nname: \"Feature2D.MSER\"\ndelta: 5\nminArea: 60\nmaxArea: 14400\nmaxVariation: 0.25\nminDiversity: 0.20000000000000001\nmaxEvolution: 200\nareaThreshold: 1.01\nminMargin: 0.0030000000000000001\nedgeBlurSize: 5\npass2Only: 0\n"; String actual = readFile(filename); actual = actual.replaceAll("e([+-])0(\\d\\d)", "e$1$2"); // NOTE: workaround for different platforms double representation assertEquals(truth, actual); diff --git a/modules/features2d/misc/java/test/ORBDescriptorExtractorTest.java b/modules/features2d/misc/java/test/ORBDescriptorExtractorTest.java index 6bc9bb6299..a1a96491f5 100644 --- a/modules/features2d/misc/java/test/ORBDescriptorExtractorTest.java +++ b/modules/features2d/misc/java/test/ORBDescriptorExtractorTest.java @@ -111,7 +111,7 @@ public class ORBDescriptorExtractorTest extends OpenCVTestCase { extractor.write(filename); - String truth = "%YAML:1.0\n---\nname: \"Feature2D.ORB\"\nnfeatures: 500\nscaleFactor: 1.2000000476837158e+00\nnlevels: 8\nedgeThreshold: 31\nfirstLevel: 0\nwta_k: 2\nscoreType: 0\npatchSize: 31\nfastThreshold: 20\n"; + String truth = "%YAML:1.0\n---\nname: \"Feature2D.ORB\"\nnfeatures: 500\nscaleFactor: 1.2000000476837158\nnlevels: 8\nedgeThreshold: 31\nfirstLevel: 0\nwta_k: 2\nscoreType: 0\npatchSize: 31\nfastThreshold: 20\n"; // String truth = "%YAML:1.0\n---\n"; String actual = readFile(filename); actual = actual.replaceAll("e\\+000", "e+00"); // NOTE: workaround for different platforms double representation diff --git a/modules/features2d/misc/java/test/SIFTDescriptorExtractorTest.java b/modules/features2d/misc/java/test/SIFTDescriptorExtractorTest.java index 63a59aa58c..dcd8564c3c 100644 --- a/modules/features2d/misc/java/test/SIFTDescriptorExtractorTest.java +++ b/modules/features2d/misc/java/test/SIFTDescriptorExtractorTest.java @@ -100,7 +100,7 @@ public class SIFTDescriptorExtractorTest extends OpenCVTestCase { extractor.write(filename); - String truth = "%YAML:1.0\n---\nname: \"Feature2D.SIFT\"\nnfeatures: 0\nnOctaveLayers: 3\ncontrastThreshold: 4.0000000000000001e-02\nedgeThreshold: 10.\nsigma: 1.6000000000000001e+00\ndescriptorType: 5\n"; + String truth = "%YAML:1.0\n---\nname: \"Feature2D.SIFT\"\nnfeatures: 0\nnOctaveLayers: 3\ncontrastThreshold: 0.040000000000000001\nedgeThreshold: 10.\nsigma: 1.6000000000000001\ndescriptorType: 5\n"; String actual = readFile(filename); actual = actual.replaceAll("e([+-])0(\\d\\d)", "e$1$2"); // NOTE: workaround for different platforms double representation assertEquals(truth, actual); diff --git a/modules/features2d/misc/java/test/SIMPLEBLOBFeatureDetectorTest.java b/modules/features2d/misc/java/test/SIMPLEBLOBFeatureDetectorTest.java index a67a0e8c3a..75817ca6b1 100644 --- a/modules/features2d/misc/java/test/SIMPLEBLOBFeatureDetectorTest.java +++ b/modules/features2d/misc/java/test/SIMPLEBLOBFeatureDetectorTest.java @@ -133,8 +133,7 @@ public class SIMPLEBLOBFeatureDetectorTest extends OpenCVTestCase { String filename = OpenCVTestRunner.getTempFileName("xml"); detector.write(filename); - - String truth = "\n\n3\n10.\n50.\n220.\n2\n10.\n1\n0\n1\n25.\n5000.\n0\n8.0000001192092896e-01\n3.4028234663852886e+38\n1\n1.0000000149011612e-01\n3.4028234663852886e+38\n1\n9.4999998807907104e-01\n3.4028234663852886e+38\n0\n\n"; + String truth = "\n\n3\n10.\n50.\n220.\n2\n10.\n1\n0\n1\n25.\n5000.\n0\n0.80000001192092896\n3.4028234663852886e+38\n1\n0.10000000149011612\n3.4028234663852886e+38\n1\n0.94999998807907104\n3.4028234663852886e+38\n0\n\n"; assertEquals(truth, readFile(filename)); } }