Quellcode durchsuchen

Add ctk::significantDecimals: a"user friendly" value decimal count

For a given value, returns a significant number of decimals (min 0, max 16)
For example, returns 2 for the value: 123456.119999999995343
Julien Finet vor 14 Jahren
Ursprung
Commit
fd0357cf31

+ 2 - 0
Libs/Core/Testing/Cpp/CMakeLists.txt

@@ -32,6 +32,7 @@ SET(KITTests_SRCS
   ctkModelTesterTest1.cpp
   ctkUtilsTest1.cpp
   ctkUtilsTest2.cpp
+  ctkUtilsTest3.cpp
   ctkDependencyGraphTest1.cpp
   ctkDependencyGraphTest2.cpp
   ctkPimplTest1.cpp
@@ -122,6 +123,7 @@ SIMPLE_TEST( ctkPimplTest1 )
 SIMPLE_TEST( ctkSingletonTest1 )
 SIMPLE_TEST( ctkUtilsTest1 )
 SIMPLE_TEST( ctkUtilsTest2 )
+SIMPLE_TEST( ctkUtilsTest3 )
 SIMPLE_TEST( ctkWorkflowTest1 )
 SIMPLE_TEST( ctkWorkflowTest2 )
 SIMPLE_TEST( ctkWorkflowTest3 )

+ 136 - 0
Libs/Core/Testing/Cpp/ctkUtilsTest3.cpp

@@ -0,0 +1,136 @@
+/*=========================================================================
+
+  Library:   CTK
+
+  Copyright (c) Kitware Inc.
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.commontk.org/LICENSE
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+=========================================================================*/
+
+// Qt includes
+#include <QDebug>
+#include <QStringList>
+
+// CTK includes
+#include "ctkUtils.h"
+
+// STD includes
+#include <stdlib.h>
+#include <iostream>
+#include <string>
+#include <vector>
+
+bool testSignificantDecimals(double value, int expected)
+{
+  int decimals = ctk::significantDecimals(value);
+  if (decimals != expected)
+    {
+    std::cerr << std::fixed << value << " decimals: " << decimals << " -> " << expected << std::endl;
+    return false;
+    }
+  return true;
+}
+
+//-----------------------------------------------------------------------------
+int ctkUtilsTest3(int , char *  [] )
+{
+  std::cout.precision(16);
+  if (testSignificantDecimals(123456., 0))
+    {
+    return EXIT_FAILURE;
+    }
+  if (testSignificantDecimals(123456.1, 1))
+    {
+    return EXIT_FAILURE;
+    }
+  if (testSignificantDecimals(123456.12, 2))
+    {
+    return EXIT_FAILURE;
+    }
+  if (testSignificantDecimals(123456.123, 3))
+    {
+    return EXIT_FAILURE;
+    }
+  if (testSignificantDecimals(123456.122, 3))
+    {
+    return EXIT_FAILURE;
+    }
+  if (testSignificantDecimals(123456.1223, 4))
+    {
+    return EXIT_FAILURE;
+    }
+  if (testSignificantDecimals(123456.1234, 4))
+    {
+    return EXIT_FAILURE;
+    }
+  if (testSignificantDecimals(123456.0123, 4))
+    {
+    return EXIT_FAILURE;
+    }
+  if (testSignificantDecimals(123456.0012, 4))
+    {
+    return EXIT_FAILURE;
+    }
+  if (testSignificantDecimals(123456.001234, 6))
+    {
+    return EXIT_FAILURE;
+    }
+  if (testSignificantDecimals(123456.000123, 6))
+    {
+    return EXIT_FAILURE;
+    }
+  if (testSignificantDecimals(123456.0000, 0))
+    {
+    return EXIT_FAILURE;
+    }
+  if (testSignificantDecimals(123456.0001, 4))
+    {
+    return EXIT_FAILURE;
+    }
+  if (testSignificantDecimals(123456.3333333, 2))
+    {
+    return EXIT_FAILURE;
+    }
+  if (testSignificantDecimals(123456.1333333, 3))
+    {
+    return EXIT_FAILURE;
+    }
+  if (testSignificantDecimals(123456.3333334, 2))
+    {
+    return EXIT_FAILURE;
+    }
+  if (testSignificantDecimals(123456.00122, 5))
+    {
+    return EXIT_FAILURE;
+    }
+  if (testSignificantDecimals(123456.00123, 5))
+    {
+    return EXIT_FAILURE;
+    }
+  // internally representated as 123456.001109999997425
+  if (testSignificantDecimals(123456.00111, 5))
+    {
+    return EXIT_FAILURE;
+    }
+  // internally representated as 123456.270000000004075
+  if (testSignificantDecimals(123456.26999999999999996, 2))
+    {
+    return EXIT_FAILURE;
+    }
+  if (testSignificantDecimals(123456.863899999999987, 4))
+    {
+    return EXIT_FAILURE;
+    }
+  return EXIT_SUCCESS;
+}

+ 51 - 0
Libs/Core/ctkUtils.cpp

@@ -19,6 +19,7 @@
 =========================================================================*/
 
 // Qt includes
+#include <QDebug>
 #include <QRegExp>
 #include <QString>
 #include <QStringList>
@@ -157,3 +158,53 @@ QRegExp ctk::nameFiltersToRegExp(const QStringList& nameFilters)
     }
   return QRegExp(pattern);
 }
+
+//-----------------------------------------------------------------------------
+int ctk::significantDecimals(double value)
+{
+  QString number = QString::number(value, 'f', 16);
+  QString fractional = number.section('.', 1, 1);
+  if (fractional.length() <= 2)
+    {
+    return fractional.length() - 1;
+    }
+  QChar previous;
+  int previousRepeat=0;
+  bool only0s = true;
+  for (int i = 0; i < fractional.length(); ++i)
+    {
+    QChar digit = fractional.at(i);
+    if (digit != '0')
+      {
+      only0s = false;
+      }
+    if (digit == previous && previousRepeat == 2 &&
+        !only0s)
+      {
+      if (digit == '0' || digit == '9')
+        {
+        return i - previousRepeat;
+        }
+      return i;
+      }
+    if (i == fractional.length() - 1)
+      {
+      if (previousRepeat > 2)
+        {
+        return i - previousRepeat;
+        }
+      return i;
+      }
+    // get ready for next
+    if (previous != digit)
+      {
+      previous = digit;
+      previousRepeat = 1;
+      }
+    else
+      {
+      ++previousRepeat;
+      }
+    }
+  return -1;
+}

+ 5 - 0
Libs/Core/ctkUtils.h

@@ -74,6 +74,11 @@ QString CTK_CORE_EXPORT extensionToRegExp(const QString& extension);
 /// "*.jpg", "*.txt" -> "(.*\\.jpg?$|.*\\.txt?$)"
 QRegExp CTK_CORE_EXPORT nameFiltersToRegExp(const QStringList& nameFilters);
 
+///
+/// \ingroup Core
+/// Return a "smart" number of decimals needed to display (in a gui) a floating
+/// number.
+int CTK_CORE_EXPORT significantDecimals(double value);
 }
 
 #endif