瀏覽代碼

ENH: Add utility function to compute the order of magnitude

of any floating number
Julien Finet 14 年之前
父節點
當前提交
8c9a94be04
共有 4 個文件被更改,包括 186 次插入0 次删除
  1. 2 0
      Libs/Core/Testing/Cpp/CMakeLists.txt
  2. 147 0
      Libs/Core/Testing/Cpp/ctkUtilsTest4.cpp
  3. 31 0
      Libs/Core/ctkUtils.cpp
  4. 6 0
      Libs/Core/ctkUtils.h

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

@@ -35,6 +35,7 @@ SET(KITTests_SRCS
   ctkUtilsTest1.cpp
   ctkUtilsTest2.cpp
   ctkUtilsTest3.cpp
+  ctkUtilsTest4.cpp
   ctkDependencyGraphTest1.cpp
   ctkDependencyGraphTest2.cpp
   ctkPimplTest1.cpp
@@ -128,6 +129,7 @@ SIMPLE_TEST( ctkSingletonTest1 )
 SIMPLE_TEST( ctkUtilsTest1 )
 SIMPLE_TEST( ctkUtilsTest2 )
 SIMPLE_TEST( ctkUtilsTest3 )
+SIMPLE_TEST( ctkUtilsTest4 )
 SIMPLE_TEST( ctkWorkflowTest1 )
 SIMPLE_TEST( ctkWorkflowTest2 )
 SIMPLE_TEST( ctkWorkflowTest3 )

+ 147 - 0
Libs/Core/Testing/Cpp/ctkUtilsTest4.cpp

@@ -0,0 +1,147 @@
+/*=========================================================================
+
+  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 test(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 ctkUtilsTest4(int , char *  [] )
+{
+  std::cout.precision(16);
+
+  if (ctk::orderOfMagnitude(1.) != 0)
+    {
+    std::cerr << "order of magnitude failed for number:"
+              << 1. << ". Found " << ctk::orderOfMagnitude(1.)
+              << " instead of 0" << std::endl;
+    return EXIT_FAILURE;
+    }
+  if (ctk::orderOfMagnitude(2.) != 0)
+    {
+    std::cerr << "order of magnitude failed for number:"
+              << 2. << ". Found " << ctk::orderOfMagnitude(2.)
+              << " instead of 0" << std::endl;
+    return EXIT_FAILURE;
+    }
+
+  if (ctk::orderOfMagnitude(10.) != 1)
+    {
+    std::cerr << "order of magnitude failed for number:"
+              << 10. << ". Found " << ctk::orderOfMagnitude(10.)
+              << " instead of 1" << std::endl;
+    return EXIT_FAILURE;
+    }
+
+  if (ctk::orderOfMagnitude(11.) != 1)
+    {
+    std::cerr << "order of magnitude failed for number:"
+              << 11. << ". Found " << ctk::orderOfMagnitude(11.)
+              << " instead of 1" << std::endl;
+    return EXIT_FAILURE;
+    }
+
+  if (ctk::orderOfMagnitude(0.1) != -1)
+    {
+    std::cerr << "order of magnitude failed for number:"
+              << 0.1 << ". Found " << ctk::orderOfMagnitude(0.1)
+              << " instead of -1" << std::endl;
+    return EXIT_FAILURE;
+    }
+
+  if (ctk::orderOfMagnitude(0.11) != -1)
+    {
+    std::cerr << "order of magnitude failed for number:"
+              << 0.11 << ". Found " << ctk::orderOfMagnitude(0.11)
+              << " instead of -1" << std::endl;
+    return EXIT_FAILURE;
+    }
+
+  if (ctk::orderOfMagnitude(0.2) != -1)
+    {
+    std::cerr << "order of magnitude failed for number:"
+              << 0.2 << ". Found " << ctk::orderOfMagnitude(0.2)
+              << " instead of -1" << std::endl;
+    return EXIT_FAILURE;
+    }
+
+  if (ctk::orderOfMagnitude(0.01) != -2)
+    {
+    std::cerr << "order of magnitude failed for number:"
+              << 0.01 << ". Found " << ctk::orderOfMagnitude(0.01)
+              << " instead of -2" << std::endl;
+    return EXIT_FAILURE;
+    }
+
+  if (ctk::orderOfMagnitude(0.0000000001) != -10)
+    {
+    std::cerr << "order of magnitude failed for number:"
+              << 0.0000000001 << ". Found " << ctk::orderOfMagnitude(0.0000000001)
+              << " instead of -10" << std::endl;
+    return EXIT_FAILURE;
+    }
+
+  if (ctk::orderOfMagnitude(10.0001) != 1)
+    {
+    std::cerr << "order of magnitude failed for number:"
+              << 10.0001 << ". Found " << ctk::orderOfMagnitude(10.0001)
+              << " instead of 1" << std::endl;
+    return EXIT_FAILURE;
+    }
+
+  if (ctk::orderOfMagnitude(100000000000.0001) != 11)
+    {
+    std::cerr << "order of magnitude failed for number:"
+              << 100000000000.0001 << ". Found " << ctk::orderOfMagnitude(100000000000.0001)
+              << " instead of 11" << std::endl;
+    return EXIT_FAILURE;
+    }
+
+  if (ctk::orderOfMagnitude(100000000001.0001) != 11)
+    {
+    std::cerr << "order of magnitude failed for number:"
+              << 100000000001.0001 << ". Found " << ctk::orderOfMagnitude(100000000001.0001)
+              << " instead of 11" << std::endl;
+    return EXIT_FAILURE;
+    }
+
+
+  return EXIT_SUCCESS;
+}

+ 31 - 0
Libs/Core/ctkUtils.cpp

@@ -28,6 +28,7 @@
 
 // STD includes
 #include <algorithm>
+#include <limits>
 
 #ifdef _MSC_VER
   #pragma warning(disable: 4996)
@@ -208,3 +209,33 @@ int ctk::significantDecimals(double value)
     }
   return -1;
 }
+
+int ctk::orderOfMagnitude(double value)
+{
+  value = qAbs(value);
+  if (value == 0.)
+    {
+    return std::numeric_limits<int>::min();
+    }
+  double magnitude = 1.00000000000000001;
+  int magnitudeOrder = 0;
+
+  int magnitudeStep = 1;
+  double magnitudeFactor = 10;
+
+  if (value < 1.)
+    {
+    magnitudeOrder = -1;
+    magnitudeStep = -1;
+    magnitudeFactor = 0.1;
+    }
+
+  while ( (magnitudeStep > 0 && value >= magnitude) ||
+          (magnitudeStep < 0 && value < magnitude - std::numeric_limits<double>::epsilon()))
+    {
+    magnitude *= magnitudeFactor;
+    magnitudeOrder += magnitudeStep;
+    }
+  // we went 1 order too far, so decrement it
+  return magnitudeOrder - magnitudeStep;
+}

+ 6 - 0
Libs/Core/ctkUtils.h

@@ -79,6 +79,12 @@ QRegExp CTK_CORE_EXPORT nameFiltersToRegExp(const QStringList& nameFilters);
 /// Return a "smart" number of decimals needed to display (in a gui) a floating
 /// number.
 int CTK_CORE_EXPORT significantDecimals(double value);
+
+///
+/// \ingroup Core
+/// Return the order of magnitude of a number.
+int CTK_CORE_EXPORT orderOfMagnitude(double value);
+
 }
 
 #endif