lmi-commits
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[lmi-commits] [lmi] master 44ea8a5b 4/4: Implement TAOCP 4.6.3


From: Greg Chicares
Subject: [lmi-commits] [lmi] master 44ea8a5b 4/4: Implement TAOCP 4.6.3
Date: Sun, 29 May 2022 20:51:23 -0400 (EDT)

branch: master
commit 44ea8a5babd25935e0cf26352af3b39bd3664940
Author: Gregory W. Chicares <gchicares@sbcglobal.net>
Commit: Gregory W. Chicares <gchicares@sbcglobal.net>

    Implement TAOCP 4.6.3
---
 bin_exp.cpp      |  39 +++++++
 bin_exp.hpp      |  49 +++++++++
 bin_exp_test.cpp | 321 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 409 insertions(+)

diff --git a/bin_exp.cpp b/bin_exp.cpp
index c590615e..afda64ba 100644
--- a/bin_exp.cpp
+++ b/bin_exp.cpp
@@ -22,3 +22,42 @@
 #include "pchfile.hpp"
 
 #include "bin_exp.hpp"
+
+#include <cstdio>                       // printf()
+
+/// Binary method for exponentiation.
+///
+/// See Knuth, TAOCP volume 2, section 4.6.3 (p. 442 in 2nd ed.).
+
+double Algorithm_A(double x, int n)
+{
+    if(n <= 0) throw "n must be positive";
+    int mult_count {0};
+//A1:
+    int    N {n};
+    double Y {1.0};
+    double Z {x};
+    std::printf("               %3s  %7s  %7s\n"  , "N", "Y", "Z");
+    std::printf("After step A1  %3i  %7.f  %7.f\n",  N,   Y,   Z );
+  A2: // [Halve N.] (At this point, x^n = Y * Z^N .)
+    bool was_even = 0 == N % 2;
+std::printf("%40s  %3i %s\n", "A2:", N, was_even ? "even" : "odd");
+    N /= 2; // integer division truncates
+    if(was_even) goto A5;
+//A3: // [Multiply Y by Z.]
+std::printf("%40s #%i %7.f × %7.f → %7.f\n", "A3:", mult_count, Y, Z, Y*Z);
+    Y *= Z;
+    ++mult_count;
+//A4: // [N == 0?]
+    std::printf("After step A4  %3i  %7.f  %7.f\n",  N,   Y,   Z );
+    if(0 == N)
+        {
+        std::printf("Algorithm A: %i multiplications\n\n", mult_count);
+        return Y;
+        }
+  A5: // [Square Z.]
+std::printf("%40s #%i %7.f ^ %7.f → %7.f\n", "A5:", mult_count, Z, 2.0, Z*Z);
+    Z *= Z;
+    ++mult_count;
+    goto A2;
+}
diff --git a/bin_exp.hpp b/bin_exp.hpp
index 445c1a9c..4027e5a1 100644
--- a/bin_exp.hpp
+++ b/bin_exp.hpp
@@ -24,4 +24,53 @@
 
 #include "config.hpp"
 
+#include <type_traits>                  // is_floating_point_v
+
+/// Binary method for exponentiation.
+///
+/// See Knuth, TAOCP volume 2, section 4.6.3, which notes (p. 443
+/// in 2nd ed.):
+///   "The number of multiplications required by Algorithm A
+///   is ⌊lg n⌋ + ν(n), where ν(n) is the number of ones in the
+///   binary representation of n. This is one more multiplication
+///   than the left-to-right binary method ... would require, due
+///   to the fact that the first execution of step A3 is simply a
+///   multiplication by unity."
+/// This seems to be an inefficiency that ought to be removed.
+/// However, initializing the result to unity takes care of the case
+/// where the exponent is zero. Attempting to remove the needless
+/// multiplication by unity, while preserving correctness when the
+/// exponent is zero, is surely possible, but several attempts just
+/// produced more complex code that ran no faster.
+///
+/// Others often write bitwise operators instead of multiplicative.
+/// That's incorrect for signed integers:
+///   (-1 % 2) = -1, whereas
+///   (-1 & 1) =  1; and
+///   (-1 / 2) =  0, whereas
+///   (-1 >>1) = -1;
+/// and twenty-first-century optimizers generate the same code for
+/// unsigned values anyway.
+
+template<typename T>
+constexpr T bin_exp(T x, int n)
+{
+    static_assert(std::is_floating_point_v<T>);
+    bool negative_exponent {n < 0};
+    if(negative_exponent) n = -n;
+    T y = 1;
+    for(;;)
+        {
+        if(0 != n % 2)
+            y *= x;
+        n /= 2;
+        if(0 == n)
+            break;
+        x *= x;
+        }
+    return negative_exponent ? 1 / y : y;
+}
+
+double Algorithm_A(double x, int n);
+
 #endif // bin_exp_hpp
diff --git a/bin_exp_test.cpp b/bin_exp_test.cpp
index a61ecde3..13c8a32d 100644
--- a/bin_exp_test.cpp
+++ b/bin_exp_test.cpp
@@ -23,9 +23,330 @@
 
 #include "bin_exp.hpp"
 
+#include "materially_equal.hpp"
+#include "stl_extensions.hpp"           // nonstd::power()
 #include "test_tools.hpp"
+#include "timer.hpp"
+
+#include <cfloat>                       // DECIMAL_DIG
+#include <cmath>                        // pow()
+#include <limits>
+
+namespace
+{
+    constexpr auto inf {std::numeric_limits<double>::infinity()};
+} // Unnamed namespace.
+
+void test_systematically()
+{
+    // powers of zero
+
+    LMI_TEST_EQUAL( 1.0, bin_exp( 0.0,  0));
+    LMI_TEST_EQUAL( 1.0, bin_exp(-0.0,  0));
+    LMI_TEST_EQUAL( 1.0, bin_exp( 0.0, -0));
+    LMI_TEST_EQUAL( 1.0, bin_exp(-0.0, -0));
+
+    LMI_TEST_EQUAL( 0.0, bin_exp( 0.0,  1));
+    LMI_TEST_EQUAL( 0.0, bin_exp(-0.0,  1));
+    LMI_TEST_EQUAL( inf, bin_exp( 0.0, -1));
+    LMI_TEST_EQUAL(-inf, bin_exp(-0.0, -1));
+
+    LMI_TEST_EQUAL( 0.0, bin_exp( 0.0,  9));
+    LMI_TEST_EQUAL( 0.0, bin_exp(-0.0,  9));
+    LMI_TEST_EQUAL( inf, bin_exp( 0.0, -9));
+    LMI_TEST_EQUAL(-inf, bin_exp(-0.0, -9));
+
+    // powers of one
+
+    LMI_TEST_EQUAL( 1.0, bin_exp( 1.0,  0));
+    LMI_TEST_EQUAL( 1.0, bin_exp(-1.0,  0));
+    LMI_TEST_EQUAL( 1.0, bin_exp( 1.0, -0));
+    LMI_TEST_EQUAL( 1.0, bin_exp(-1.0, -0));
+
+    LMI_TEST_EQUAL( 1.0, bin_exp( 1.0,  1));
+    LMI_TEST_EQUAL(-1.0, bin_exp(-1.0,  1));
+    LMI_TEST_EQUAL( 1.0, bin_exp( 1.0, -1));
+    LMI_TEST_EQUAL(-1.0, bin_exp(-1.0, -1));
+
+    // powers of e
+
+    constexpr double e     = 2.71828'18284'59045'23536;
+    constexpr double e_sq  = 7.38905'60989'30650'22723;
+    constexpr double e_101 = 7.30705'99793'68067'27265e43;
+
+    LMI_TEST_EQUAL(     1.0, bin_exp( e,  0));
+    LMI_TEST_EQUAL(     1.0, bin_exp(-e,  0));
+    LMI_TEST_EQUAL(     1.0, bin_exp( e, -0));
+    LMI_TEST_EQUAL(     1.0, bin_exp(-e, -0));
+
+    LMI_TEST_EQUAL(       e, bin_exp( e,  1));
+    LMI_TEST_EQUAL(      -e, bin_exp(-e,  1));
+    LMI_TEST_EQUAL( 1.0 / e, bin_exp( e, -1));
+    LMI_TEST_EQUAL(-1.0 / e, bin_exp(-e, -1));
+
+    LMI_TEST(materially_equal(       e_sq , bin_exp( e,    2), 1.0e-15));
+    LMI_TEST(materially_equal(       e_sq , bin_exp(-e,    2), 1.0e-15));
+    LMI_TEST(materially_equal( 1.0 / e_sq , bin_exp( e,   -2), 1.0e-16));
+    LMI_TEST(materially_equal( 1.0 / e_sq , bin_exp(-e,   -2), 1.0e-16));
+
+    LMI_TEST(materially_equal(       e_101, bin_exp( e,  101), 1.0e-14));
+    LMI_TEST(materially_equal(      -e_101, bin_exp(-e,  101), 1.0e-14));
+    LMI_TEST(materially_equal( 1.0 / e_101, bin_exp( e, -101), 1.0e-14));
+    LMI_TEST(materially_equal(-1.0 / e_101, bin_exp(-e, -101), 1.0e-14));
+
+    // [change of sign shouldn't affect absolute value]
+    LMI_TEST_EQUAL(bin_exp(-e,    2),  bin_exp( e,    2));
+    LMI_TEST_EQUAL(bin_exp(-e,   -2),  bin_exp( e,   -2));
+    LMI_TEST_EQUAL(bin_exp(-e,  101), -bin_exp( e,  101));
+    LMI_TEST_EQUAL(bin_exp(-e, -101), -bin_exp( e, -101));
+
+    LMI_TEST_EQUAL(     inf, bin_exp( e,  999));
+    LMI_TEST_EQUAL(    -inf, bin_exp(-e,  999));
+    LMI_TEST_EQUAL(     0.0, bin_exp( e, -999));
+    LMI_TEST_EQUAL(    -0.0, bin_exp(-e, -999));
+}
+
+void test_integral_powers_of_two()
+{
+    //                        00000000011111111
+    //                        12345678901234567 17 == DBL_DECIMAL_DIG
+    LMI_TEST_EQUAL(0.00000000000000011102230246251565 , bin_exp(2.0, -53));
+    LMI_TEST_EQUAL(0.00000000000000022204460492503130 , bin_exp(2.0, -52));
+    LMI_TEST_EQUAL(0.00000000000000044408920985006261 , bin_exp(2.0, -51));
+    LMI_TEST_EQUAL(0.00000000000000088817841970012523 , bin_exp(2.0, -50));
+    LMI_TEST_EQUAL(0.0000000000000017763568394002504  , bin_exp(2.0, -49));
+    LMI_TEST_EQUAL(0.0000000000000035527136788005009  , bin_exp(2.0, -48));
+    LMI_TEST_EQUAL(0.0000000000000071054273576010018  , bin_exp(2.0, -47));
+    LMI_TEST_EQUAL(0.000000000000014210854715202003   , bin_exp(2.0, -46));
+    LMI_TEST_EQUAL(0.000000000000028421709430404007   , bin_exp(2.0, -45));
+    LMI_TEST_EQUAL(0.000000000000056843418860808015   , bin_exp(2.0, -44));
+    LMI_TEST_EQUAL(0.000000000000113686837721616030   , bin_exp(2.0, -43));
+    LMI_TEST_EQUAL(0.000000000000227373675443232059   , bin_exp(2.0, -42));
+    LMI_TEST_EQUAL(0.000000000000454747350886464119   , bin_exp(2.0, -41));
+    LMI_TEST_EQUAL(0.000000000000909494701772928238   , bin_exp(2.0, -40));
+    LMI_TEST_EQUAL(0.000000000001818989403545856476   , bin_exp(2.0, -39));
+    LMI_TEST_EQUAL(0.000000000003637978807091712952   , bin_exp(2.0, -38));
+    LMI_TEST_EQUAL(0.000000000007275957614183425903   , bin_exp(2.0, -37));
+    LMI_TEST_EQUAL(0.000000000014551915228366851807   , bin_exp(2.0, -36));
+    LMI_TEST_EQUAL(0.000000000029103830456733703613   , bin_exp(2.0, -35));
+    LMI_TEST_EQUAL(0.000000000058207660913467407227   , bin_exp(2.0, -34));
+    LMI_TEST_EQUAL(0.000000000116415321826934814453   , bin_exp(2.0, -33));
+    LMI_TEST_EQUAL(0.000000000232830643653869628906   , bin_exp(2.0, -32));
+    LMI_TEST_EQUAL(0.000000000465661287307739257813   , bin_exp(2.0, -31));
+    LMI_TEST_EQUAL(0.000000000931322574615478515625   , bin_exp(2.0, -30));
+    LMI_TEST_EQUAL(0.00000000186264514923095703125    , bin_exp(2.0, -29));
+    LMI_TEST_EQUAL(0.0000000037252902984619140625     , bin_exp(2.0, -28));
+    LMI_TEST_EQUAL(0.000000007450580596923828125      , bin_exp(2.0, -27));
+    LMI_TEST_EQUAL(0.00000001490116119384765625       , bin_exp(2.0, -26));
+    LMI_TEST_EQUAL(0.0000000298023223876953125        , bin_exp(2.0, -25));
+    LMI_TEST_EQUAL(0.000000059604644775390625         , bin_exp(2.0, -24));
+    LMI_TEST_EQUAL(0.00000011920928955078125          , bin_exp(2.0, -23));
+    LMI_TEST_EQUAL(0.0000002384185791015625           , bin_exp(2.0, -22));
+    LMI_TEST_EQUAL(0.000000476837158203125            , bin_exp(2.0, -21));
+    LMI_TEST_EQUAL(0.00000095367431640625             , bin_exp(2.0, -20));
+    LMI_TEST_EQUAL(0.0000019073486328125              , bin_exp(2.0, -19));
+    LMI_TEST_EQUAL(0.000003814697265625               , bin_exp(2.0, -18));
+    LMI_TEST_EQUAL(0.00000762939453125                , bin_exp(2.0, -17));
+    LMI_TEST_EQUAL(0.0000152587890625                 , bin_exp(2.0, -16));
+    LMI_TEST_EQUAL(0.000030517578125                  , bin_exp(2.0, -15));
+    LMI_TEST_EQUAL(0.00006103515625                   , bin_exp(2.0, -14));
+    LMI_TEST_EQUAL(0.0001220703125                    , bin_exp(2.0, -13));
+    LMI_TEST_EQUAL(0.000244140625                     , bin_exp(2.0, -12));
+    LMI_TEST_EQUAL(0.00048828125                      , bin_exp(2.0, -11));
+    LMI_TEST_EQUAL(0.0009765625                       , bin_exp(2.0, -10));
+    LMI_TEST_EQUAL(0.001953125                        , bin_exp(2.0,  -9));
+    LMI_TEST_EQUAL(0.00390625                         , bin_exp(2.0,  -8));
+    LMI_TEST_EQUAL(0.0078125                          , bin_exp(2.0,  -7));
+    LMI_TEST_EQUAL(0.015625                           , bin_exp(2.0,  -6));
+    LMI_TEST_EQUAL(0.03125                            , bin_exp(2.0,  -5));
+    LMI_TEST_EQUAL(0.0625                             , bin_exp(2.0,  -4));
+    LMI_TEST_EQUAL(0.125                              , bin_exp(2.0,  -3));
+    LMI_TEST_EQUAL(0.25                               , bin_exp(2.0,  -2));
+    LMI_TEST_EQUAL(0.5                                , bin_exp(2.0,  -1));
+    LMI_TEST_EQUAL(1                                  , bin_exp(2.0,   0));
+    LMI_TEST_EQUAL(2                                  , bin_exp(2.0,   1));
+    LMI_TEST_EQUAL(4                                  , bin_exp(2.0,   2));
+    LMI_TEST_EQUAL(8                                  , bin_exp(2.0,   3));
+    LMI_TEST_EQUAL(16                                 , bin_exp(2.0,   4));
+    LMI_TEST_EQUAL(32                                 , bin_exp(2.0,   5));
+    LMI_TEST_EQUAL(64                                 , bin_exp(2.0,   6));
+    LMI_TEST_EQUAL(128                                , bin_exp(2.0,   7));
+    LMI_TEST_EQUAL(256                                , bin_exp(2.0,   8));
+    LMI_TEST_EQUAL(512                                , bin_exp(2.0,   9));
+    LMI_TEST_EQUAL(1024                               , bin_exp(2.0,  10));
+    LMI_TEST_EQUAL(2048                               , bin_exp(2.0,  11));
+    LMI_TEST_EQUAL(4096                               , bin_exp(2.0,  12));
+    LMI_TEST_EQUAL(8192                               , bin_exp(2.0,  13));
+    LMI_TEST_EQUAL(16384                              , bin_exp(2.0,  14));
+    LMI_TEST_EQUAL(32768                              , bin_exp(2.0,  15));
+    LMI_TEST_EQUAL(65536                              , bin_exp(2.0,  16));
+    LMI_TEST_EQUAL(131072                             , bin_exp(2.0,  17));
+    LMI_TEST_EQUAL(262144                             , bin_exp(2.0,  18));
+    LMI_TEST_EQUAL(524288                             , bin_exp(2.0,  19));
+    LMI_TEST_EQUAL(1048576                            , bin_exp(2.0,  20));
+    LMI_TEST_EQUAL(2097152                            , bin_exp(2.0,  21));
+    LMI_TEST_EQUAL(4194304                            , bin_exp(2.0,  22));
+    LMI_TEST_EQUAL(8388608                            , bin_exp(2.0,  23));
+    LMI_TEST_EQUAL(16777216                           , bin_exp(2.0,  24));
+    LMI_TEST_EQUAL(33554432                           , bin_exp(2.0,  25));
+    LMI_TEST_EQUAL(67108864                           , bin_exp(2.0,  26));
+    LMI_TEST_EQUAL(134217728                          , bin_exp(2.0,  27));
+    LMI_TEST_EQUAL(268435456                          , bin_exp(2.0,  28));
+    LMI_TEST_EQUAL(536870912                          , bin_exp(2.0,  29));
+    LMI_TEST_EQUAL(1073741824                         , bin_exp(2.0,  30));
+    LMI_TEST_EQUAL(2147483648                         , bin_exp(2.0,  31));
+    LMI_TEST_EQUAL(4294967296                         , bin_exp(2.0,  32));
+    LMI_TEST_EQUAL(8589934592                         , bin_exp(2.0,  33));
+    LMI_TEST_EQUAL(17179869184                        , bin_exp(2.0,  34));
+    LMI_TEST_EQUAL(34359738368                        , bin_exp(2.0,  35));
+    LMI_TEST_EQUAL(68719476736                        , bin_exp(2.0,  36));
+    LMI_TEST_EQUAL(137438953472                       , bin_exp(2.0,  37));
+    LMI_TEST_EQUAL(274877906944                       , bin_exp(2.0,  38));
+    LMI_TEST_EQUAL(549755813888                       , bin_exp(2.0,  39));
+    LMI_TEST_EQUAL(1099511627776                      , bin_exp(2.0,  40));
+    LMI_TEST_EQUAL(2199023255552                      , bin_exp(2.0,  41));
+    LMI_TEST_EQUAL(4398046511104                      , bin_exp(2.0,  42));
+    LMI_TEST_EQUAL(8796093022208                      , bin_exp(2.0,  43));
+    LMI_TEST_EQUAL(17592186044416                     , bin_exp(2.0,  44));
+    LMI_TEST_EQUAL(35184372088832                     , bin_exp(2.0,  45));
+    LMI_TEST_EQUAL(70368744177664                     , bin_exp(2.0,  46));
+    LMI_TEST_EQUAL(140737488355328                    , bin_exp(2.0,  47));
+    LMI_TEST_EQUAL(281474976710656                    , bin_exp(2.0,  48));
+    LMI_TEST_EQUAL(562949953421312                    , bin_exp(2.0,  49));
+    LMI_TEST_EQUAL(1125899906842624                   , bin_exp(2.0,  50));
+    LMI_TEST_EQUAL(2251799813685248                   , bin_exp(2.0,  51));
+    LMI_TEST_EQUAL(4503599627370496                   , bin_exp(2.0,  52));
+    LMI_TEST_EQUAL(9007199254740992                   , bin_exp(2.0,  53));
+}
+
+void test_integral_powers_of_ten()
+{
+    LMI_TEST_EQUAL(0.0000000000000001                 , bin_exp(10.0, -16));
+    LMI_TEST_EQUAL(0.000000000000001                  , bin_exp(10.0, -15));
+    LMI_TEST_EQUAL(0.00000000000001                   , bin_exp(10.0, -14));
+    LMI_TEST_EQUAL(0.0000000000001                    , bin_exp(10.0, -13));
+    LMI_TEST_EQUAL(0.000000000001                     , bin_exp(10.0, -12));
+    LMI_TEST_EQUAL(0.00000000001                      , bin_exp(10.0, -11));
+    LMI_TEST_EQUAL(0.0000000001                       , bin_exp(10.0, -10));
+    LMI_TEST_EQUAL(0.000000001                        , bin_exp(10.0,  -9));
+    LMI_TEST_EQUAL(0.00000001                         , bin_exp(10.0,  -8));
+    LMI_TEST_EQUAL(0.0000001                          , bin_exp(10.0,  -7));
+    LMI_TEST_EQUAL(0.000001                           , bin_exp(10.0,  -6));
+    LMI_TEST_EQUAL(0.00001                            , bin_exp(10.0,  -5));
+    LMI_TEST_EQUAL(0.0001                             , bin_exp(10.0,  -4));
+    LMI_TEST_EQUAL(0.001                              , bin_exp(10.0,  -3));
+    LMI_TEST_EQUAL(0.01                               , bin_exp(10.0,  -2));
+    LMI_TEST_EQUAL(0.1                                , bin_exp(10.0,  -1));
+    LMI_TEST_EQUAL(1                                  , bin_exp(10.0,   0));
+    LMI_TEST_EQUAL(10                                 , bin_exp(10.0,   1));
+    LMI_TEST_EQUAL(100                                , bin_exp(10.0,   2));
+    LMI_TEST_EQUAL(1000                               , bin_exp(10.0,   3));
+    LMI_TEST_EQUAL(10000                              , bin_exp(10.0,   4));
+    LMI_TEST_EQUAL(100000                             , bin_exp(10.0,   5));
+    LMI_TEST_EQUAL(1000000                            , bin_exp(10.0,   6));
+    LMI_TEST_EQUAL(10000000                           , bin_exp(10.0,   7));
+    LMI_TEST_EQUAL(100000000                          , bin_exp(10.0,   8));
+    LMI_TEST_EQUAL(1000000000                         , bin_exp(10.0,   9));
+    LMI_TEST_EQUAL(10000000000                        , bin_exp(10.0,  10));
+    LMI_TEST_EQUAL(100000000000                       , bin_exp(10.0,  11));
+    LMI_TEST_EQUAL(1000000000000                      , bin_exp(10.0,  12));
+    LMI_TEST_EQUAL(10000000000000                     , bin_exp(10.0,  13));
+    LMI_TEST_EQUAL(100000000000000                    , bin_exp(10.0,  14));
+    LMI_TEST_EQUAL(1000000000000000                   , bin_exp(10.0,  15));
+    LMI_TEST_EQUAL(10000000000000000                  , bin_exp(10.0,  16));
+}
+
+void test_quodlibet()
+{
+    // Rust issue 73420:
+    //             0000 0000011111111
+    //             1234 5678901234567 17 == DBL_DECIMAL_DIG
+    // Wolfram:    1748.219590818327062731185606025974266231060028076171875
+    LMI_TEST_EQUAL(1748.2195908183271, bin_exp(12.04662322998046875, 3));
+
+    // Comparison to std::pow() and nonstd::power().
+    double a0 = std::pow
+        (static_cast<double>(std::numeric_limits<double>::radix)
+        ,static_cast<double>(std::numeric_limits<double>::digits)
+        );
+    double a1 = nonstd::power
+        (static_cast<double>(std::numeric_limits<double>::radix)
+        ,                    std::numeric_limits<double>::digits
+        );
+    // This compiles, but its behavior is undefined unless an int
+    // is at least 54 bits (53, + 1 for sign). Otherwise it cannot
+    // return the hoped-for answer, and may return zero.
+    auto a2 = nonstd::power
+        (                    std::numeric_limits<double>::radix
+        ,                    std::numeric_limits<double>::digits
+        );
+    auto a3 = nonstd::power
+        (static_cast<long int>(std::numeric_limits<double>::radix)
+        ,static_cast<long int>(std::numeric_limits<double>::digits)
+        );
+    LMI_TEST_EQUAL(9007199254740992, a0);
+    LMI_TEST_EQUAL(9007199254740992, a1);
+    stifle_unused_warning(a2);
+    stifle_unused_warning(a3);
+}
+
+void mete0()
+{
+    double volatile x;
+    for(int j = 0; j < 100000; ++j)
+        for(int k = 0; k < 32; ++k)
+            {x = bin_exp(2.0, 1 + k);}
+    stifle_unused_warning(x);
+}
+
+void mete1()
+{
+    double volatile x;
+    for(int j = 0; j < 100000; ++j)
+        for(int k = 0; k < 32; ++k)
+            {x = nonstd::power(2.0, 1 + k);}
+    stifle_unused_warning(x);
+}
+
+void mete2()
+{
+    double volatile x;
+    for(int j = 0; j < 100000; ++j)
+        for(int k = 0; k < 32; ++k)
+            {x = std::pow(2.0, 1 + k);}
+    stifle_unused_warning(x);
+}
+
+void assay_speed()
+{
+    std::cout << "Speed tests ['power' limits the domain]:\n";
+    std::cout << "  bin_exp " << TimeAnAliquot(mete0) << '\n';
+    std::cout << "  power   " << TimeAnAliquot(mete1) << '\n';
+    std::cout << "  pow     " << TimeAnAliquot(mete2) << '\n';
+    std::cout << std::flush;
+}
 
 int test_main(int, char*[])
 {
+    // This affects diagnostics shown when LMI_TEST_EQUAL() fails.
+    std::cout.precision(DECIMAL_DIG);
+
+    test_systematically();
+    test_integral_powers_of_two();
+    test_integral_powers_of_ten();
+    test_quodlibet();
+
+    // Optional demonstration.
+    //
+    // A reviewer asked whether the example on page 442 is right:
+    // shouldn't the "Z" column go from x^4 to x^8 in the last
+    // row (rather than from x^4 to x^16 as shown), since squaring
+    // x^4 yields x^8? This explains why the book is correct.
+
+    LMI_TEST(8388608 == Algorithm_A(2.0, 23));
+    LMI_TEST(8388608 == bin_exp    (2.0, 23));
+
+    assay_speed();
+
     return 0;
 }



reply via email to

[Prev in Thread] Current Thread [Next in Thread]