commit c7e0510c8171008a37eb1b4465dd9f04e61cdf3f
Author: David Sorber <david.sorber@gmail.com>
Date:   Sun Feb 20 16:59:02 2022 -0500

    Fix minor bug in int128.h. Also add initial unit tests.

diff --git a/software/fixed/.clang-format b/software/fixed/.clang-format
new file mode 100644
index 0000000..290cd0b
--- /dev/null
+++ b/software/fixed/.clang-format
@@ -0,0 +1,224 @@
+---
+Language:        Cpp
+# BasedOnStyle:  Google
+AccessModifierOffset: -1
+AlignAfterOpenBracket: DontAlign
+AlignArrayOfStructures: Right
+AlignConsecutiveMacros: None
+AlignConsecutiveAssignments: None
+AlignConsecutiveBitFields: AcrossComments
+AlignConsecutiveDeclarations: None
+AlignEscapedNewlines: Right
+AlignOperands:   Align
+AlignTrailingComments: false
+AllowAllArgumentsOnNextLine: true
+AllowAllParametersOfDeclarationOnNextLine: true
+AllowShortEnumsOnASingleLine: true
+AllowShortBlocksOnASingleLine: Never
+AllowShortCaseLabelsOnASingleLine: false
+AllowShortFunctionsOnASingleLine: InlineOnly
+AllowShortLambdasOnASingleLine: All
+AllowShortIfStatementsOnASingleLine: Never
+AllowShortLoopsOnASingleLine: false
+AlwaysBreakAfterDefinitionReturnType: None
+AlwaysBreakAfterReturnType: None
+AlwaysBreakBeforeMultilineStrings: false
+AlwaysBreakTemplateDeclarations: Yes
+AttributeMacros:
+  - __capability
+BasedOnStyle:    ''
+BinPackArguments: false
+BinPackParameters: false
+BitFieldColonSpacing: Both
+BraceWrapping:
+  AfterCaseLabel:  true
+  AfterClass:      false
+  AfterControlStatement: Always
+  AfterEnum:       true
+  AfterFunction:   true
+  AfterNamespace:  false
+  AfterObjCDeclaration: false
+  AfterStruct:     true
+  AfterUnion:      true
+  AfterExternBlock: true
+  BeforeCatch:     true
+  BeforeElse:      true
+  BeforeLambdaBody: false
+  BeforeWhile:     false
+  IndentBraces:    false
+  SplitEmptyFunction: false
+  SplitEmptyRecord: false
+  SplitEmptyNamespace: false
+BreakAfterJavaFieldAnnotations: false
+BreakBeforeBinaryOperators: NonAssignment
+BreakBeforeBraces: Custom
+BreakBeforeConceptDeclarations: true
+BreakBeforeTernaryOperators: false
+BreakBeforeInheritanceComma: false
+BreakConstructorInitializers: BeforeColon
+BreakInheritanceList: BeforeColon
+BreakStringLiterals: true
+ColumnLimit:     80
+CommentPragmas:  '^ IWYU pragma:'
+CompactNamespaces: false
+ConstructorInitializerIndentWidth: 4
+ContinuationIndentWidth: 4
+Cpp11BracedListStyle: true
+DeriveLineEnding: true
+DerivePointerAlignment: false
+DisableFormat:   false
+EmptyLineAfterAccessModifier: Always
+EmptyLineBeforeAccessModifier: LogicalBlock
+ExperimentalAutoDetectBinPacking: false
+FixNamespaceComments: true
+ForEachMacros:
+  - foreach
+  - Q_FOREACH
+  - BOOST_FOREACH
+IfMacros:
+  - KJ_IF_MAYBE
+IncludeBlocks:   Regroup
+IncludeCategories:
+  - Regex:           '^<ext/.*\.h>'
+    Priority:        2
+    SortPriority:    0
+    CaseSensitive:   false
+  - Regex:           '^<.*\.h>'
+    Priority:        1
+    SortPriority:    0
+    CaseSensitive:   false
+  - Regex:           '^<.*'
+    Priority:        2
+    SortPriority:    0
+    CaseSensitive:   false
+  - Regex:           '.*'
+    Priority:        3
+    SortPriority:    0
+    CaseSensitive:   false
+IncludeIsMainRegex: '([-_](test|unittest))?$'
+IncludeIsMainSourceRegex: ''
+IndentAccessModifiers: false
+IndentCaseBlocks: false
+IndentCaseLabels: true
+IndentExternBlock: AfterExternBlock
+IndentGotoLabels: false
+IndentPPDirectives: None
+IndentRequires:  false
+IndentWidth:     4
+IndentWrappedFunctionNames: false
+InsertTrailingCommas: None
+JavaScriptQuotes: Leave
+JavaScriptWrapImports: true
+KeepEmptyLinesAtTheStartOfBlocks: false
+LambdaBodyIndentation: Signature
+MacroBlockBegin: ''
+MacroBlockEnd:   ''
+MaxEmptyLinesToKeep: 1
+NamespaceIndentation: None
+ObjCBinPackProtocolList: Never
+ObjCBlockIndentWidth: 2
+ObjCBreakBeforeNestedBlockParam: true
+ObjCSpaceAfterProperty: false
+ObjCSpaceBeforeProtocolList: true
+PackConstructorInitializers: Never
+PenaltyBreakAssignment: 2
+PenaltyBreakBeforeFirstCallParameter: 1
+PenaltyBreakComment: 300
+PenaltyBreakFirstLessLess: 120
+PenaltyBreakOpenParenthesis: 0
+PenaltyBreakString: 1000
+PenaltyBreakTemplateDeclaration: 10
+PenaltyExcessCharacter: 1000000
+PenaltyReturnTypeOnItsOwnLine: 200
+PenaltyIndentedWhitespace: 0
+PointerAlignment: Left
+PPIndentWidth:   -1
+QualifierAlignment: Leave
+#QualifierOrder: ['static', 'inline', 'const', 'type', 'volatile' ]
+RawStringFormats:
+  - Language:        Cpp
+    Delimiters:
+      - cc
+      - CC
+      - cpp
+      - Cpp
+      - CPP
+      - 'c++'
+      - 'C++'
+    CanonicalDelimiter: ''
+    BasedOnStyle:    google
+  - Language:        TextProto
+    Delimiters:
+      - pb
+      - PB
+      - proto
+      - PROTO
+    EnclosingFunctions:
+      - EqualsProto
+      - EquivToProto
+      - PARSE_PARTIAL_TEXT_PROTO
+      - PARSE_TEST_PROTO
+      - PARSE_TEXT_PROTO
+      - ParseTextOrDie
+      - ParseTextProtoOrDie
+      - ParseTestProto
+      - ParsePartialTestProto
+    CanonicalDelimiter: pb
+    BasedOnStyle:    google
+ReferenceAlignment: Pointer
+ReflowComments:  true
+RemoveBracesLLVM: false
+SeparateDefinitionBlocks: Leave
+ShortNamespaceLines: 1
+SortIncludes:    CaseSensitive
+SortJavaStaticImport: Before
+SortUsingDeclarations: true
+SpaceAfterCStyleCast: false
+SpaceAfterLogicalNot: true
+SpaceAfterTemplateKeyword: false
+SpaceAroundPointerQualifiers: Default
+SpaceBeforeAssignmentOperators: true
+SpaceBeforeCaseColon: false
+SpaceBeforeCpp11BracedList: false
+SpaceBeforeCtorInitializerColon: true
+SpaceBeforeInheritanceColon: true
+SpaceBeforeParens: ControlStatements
+SpaceBeforeParensOptions:
+  AfterControlStatements: true
+  AfterForeachMacros: true
+  AfterFunctionDefinitionName: false
+  AfterFunctionDeclarationName: false
+  AfterIfMacros:   true
+  AfterOverloadedOperator: false
+  BeforeNonEmptyParentheses: false
+SpaceBeforeRangeBasedForLoopColon: true
+SpaceBeforeSquareBrackets: false
+SpaceInEmptyBlock: false
+SpaceInEmptyParentheses: false
+SpacesBeforeTrailingComments: 2
+SpacesInAngles:  Never
+SpacesInCStyleCastParentheses: false
+SpacesInConditionalStatement: false
+SpacesInContainerLiterals: true
+SpacesInLineCommentPrefix:
+  Minimum:         1
+  Maximum:         -1
+SpacesInParentheses: false
+SpacesInSquareBrackets: false
+Standard:        c++17
+StatementAttributeLikeMacros:
+  - Q_EMIT
+StatementMacros:
+  - Q_UNUSED
+  - QT_REQUIRE_VERSION
+TabWidth:        4
+UseCRLF:         false
+UseTab:          Never
+WhitespaceSensitiveMacros:
+  - STRINGIZE
+  - PP_STRINGIZE
+  - BOOST_PP_STRINGIZE
+  - NS_SWIFT_NAME
+  - CF_SWIFT_NAME
+...
+
diff --git a/software/fixed/CMakeLists.txt b/software/fixed/CMakeLists.txt
index 03c314a..fba5367 100644
--- a/software/fixed/CMakeLists.txt
+++ b/software/fixed/CMakeLists.txt
@@ -5,16 +5,27 @@ SET(CMAKE_CXX_STANDARD 17)
 
 INCLUDE_DIRECTORIES(.)
 
-#~ SET(EXTERNAL_LIBS)
+SET(EXTERNAL_LIBS)
 #~ FIND_PACKAGE(Threads)
-#~ FIND_PACKAGE(Boost 1.58.0 COMPONENTS system regex program_options filesystem REQUIRED)
-#~ IF (Boost_FOUND)
-   #~ INCLUDE_DIRECTORIES(${Boost_INCLUDE_DIRS})
-   #~ SET(EXTERNAL_LIBS ${EXTERNAL_LIBS} ${Boost_LIBRARIES})
-#~ ENDIF()
+FIND_PACKAGE(Boost 1.58.0 COMPONENTS system unit_test_framework REQUIRED)
+IF (Boost_FOUND)
+   INCLUDE_DIRECTORIES(${Boost_INCLUDE_DIRS})
+   SET(EXTERNAL_LIBS ${EXTERNAL_LIBS} ${Boost_LIBRARIES})
+ENDIF()
 
 
 SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -O3 -march=native -fuse-ld=gold -flto")
 
-ADD_EXECUTABLE(fixed_test ${CMAKE_CURRENT_SOURCE_DIR}/fixed_test.cc)
+ADD_EXECUTABLE(fixed_util ${CMAKE_CURRENT_SOURCE_DIR}/fixed_util.cc)
 ADD_EXECUTABLE(parse_test ${CMAKE_CURRENT_SOURCE_DIR}/parse_test.cc)
+
+# Test executables
+ADD_EXECUTABLE(fixed_test ${CMAKE_CURRENT_SOURCE_DIR}/fixed_test.cc)
+TARGET_LINK_LIBRARIES(fixed_test ${EXTERNAL_LIBS})
+
+ADD_EXECUTABLE(int128_test ${CMAKE_CURRENT_SOURCE_DIR}/int128_test.cc)
+TARGET_LINK_LIBRARIES(int128_test ${EXTERNAL_LIBS})
+
+ADD_TEST(NAME test_int128t COMMAND int128_test)
+ADD_TEST(NAME test_fixed COMMAND fixed_test)
+
diff --git a/software/fixed/fixed.h b/software/fixed/fixed.h
index ecb6938..f8d5656 100644
--- a/software/fixed/fixed.h
+++ b/software/fixed/fixed.h
@@ -4,62 +4,70 @@
 
 #include <cctype>
 #include <cmath>
-#include <cstdlib>
 #include <cstdint>
+#include <cstdlib>
 #include <iomanip>
 #include <iostream>
 #include <limits>
-#include <stdexcept>
 #include <sstream>
+#include <stdexcept>
 #include <type_traits>
 
 #if __GNUC__ >= 3
-# define __unlikely(cond)	__builtin_expect ((cond), 0)
-# define __likely(cond)	__builtin_expect ((cond), 1)
+#define __unlikely(cond) __builtin_expect((cond), 0)
+#define __likely(cond)   __builtin_expect((cond), 1)
 #else
-# define __unlikely(cond)	(cond)
-# define __likely(cond)	(cond)
+#define __unlikely(cond) (cond)
+#define __likely(cond)   (cond)
 #endif
 
-template <typename IntegerType, typename FractionalType>
-class fixed
+template<typename IntegerType, typename FractionalType>
+class fixed 
 {
-    static_assert(std::is_integral<IntegerType>::value, "IntegerType must be an integral type");
-    static_assert(std::is_integral<FractionalType>::value, "FractionalType must be an integral type");
-    
-    static_assert(std::is_signed<IntegerType>::value, "IntegerType must be a signed type");
-    static_assert(std::is_unsigned<FractionalType>::value, "FractionalType must be an unsigned type");
-    
+    static_assert(std::is_integral<IntegerType>::value,
+                  "IntegerType must be an integral type");
+    static_assert(std::is_integral<FractionalType>::value,
+                  "FractionalType must be an integral type");
+
+    static_assert(std::is_signed<IntegerType>::value,
+                  "IntegerType must be a signed type");
+    static_assert(std::is_unsigned<FractionalType>::value,
+                  "FractionalType must be an unsigned type");
+
 public:
 
     static constexpr size_t integer_bits = sizeof(IntegerType) * 8;
     static constexpr size_t fractional_bits = sizeof(FractionalType) * 8;
-    
-    static constexpr size_t integer_decimal_digits = std::floor(std::log10(std::numeric_limits<IntegerType>::max()));
-    static constexpr size_t fractional_decimal_digits = std::floor(std::log10(std::numeric_limits<FractionalType>::max()));
-    
-    static constexpr size_t MAX_INTEGER_VALUE = (static_cast<uint64_t>(std::pow(10, integer_decimal_digits)) - 1);
+
+    static constexpr size_t integer_decimal_digits =
+        std::floor(std::log10(std::numeric_limits<IntegerType>::max()));
+    static constexpr size_t fractional_decimal_digits =
+        std::floor(std::log10(std::numeric_limits<FractionalType>::max()));
+
+    static constexpr size_t MAX_INTEGER_VALUE =
+        (static_cast<uint64_t>(std::pow(10, integer_decimal_digits)) - 1);
     static constexpr size_t MIN_INTEGER_VALUE = 0;
-    
-    static constexpr size_t MAX_FRACTIONAL_VALUE = (static_cast<uint64_t>(std::pow(10, fractional_decimal_digits)) - 1);
+
+    static constexpr size_t MAX_FRACTIONAL_VALUE =
+        (static_cast<uint64_t>(std::pow(10, fractional_decimal_digits)) - 1);
     static constexpr size_t MIN_FRACTIONAL_VALUE = 0;
-    
+
     static const uint64_t SCALE_VALUES[20];
-    
+
     // Constructors
     fixed()
-        : m_integer(0), 
-          m_fractional(0) 
+        : m_integer(0),
+          m_fractional(0)
     {}
-    
+
     fixed(IntegerType integerVal)
-        : m_integer(__checkIntOverflow(integerVal)), 
-          m_fractional(0) 
+        : m_integer(__checkIntOverflow(integerVal)),
+          m_fractional(0)
     {}
-        
+
     fixed(IntegerType integerVal, FractionalType fractionalVal)
-        : m_integer(__checkIntOverflow(integerVal)), 
-          m_fractional(__checkFracOverflow(fractionalVal)) 
+        : m_integer(__checkIntOverflow(integerVal)),
+          m_fractional(__checkFracOverflow(fractionalVal))
     {
         // Scale the fractional value appropriately
         uint32_t idx = 0;
@@ -70,15 +78,15 @@ public:
                 break;
             }
         }
-        
-        m_fractional = __checkFracOverflow(m_fractional * 
-                                           SCALE_VALUES[fractional_decimal_digits - idx]);
+
+        m_fractional = __checkFracOverflow(
+            m_fractional * SCALE_VALUES[fractional_decimal_digits - idx]);
     }
-    
+
     // Default copy constructor, and assignment operator
-	fixed(const fixed&) = default;
-	fixed& operator=(const fixed&) = default;
-    
+    fixed(const fixed&) = default;
+    fixed& operator=(const fixed&) = default;
+
     // Reassign value to type
     void assign(IntegerType integerVal, FractionalType fractionalVal)
     {
@@ -92,73 +100,79 @@ public:
                 break;
             }
         }
-        
-        m_fractional = __checkFracOverflow(fractionalVal * 
-                                           SCALE_VALUES[fractional_decimal_digits - idx]);
+
+        m_fractional = __checkFracOverflow(
+            fractionalVal * SCALE_VALUES[fractional_decimal_digits - idx]);
     }
-    
+
     // Parse value from string input
     uint32_t parse(const char* input)
     {
         char* endPtr = nullptr;
-        m_integer = __checkIntOverflow(strtoull(input, &endPtr, 10));
+        m_integer = __checkIntOverflow(strtoll(input, &endPtr, 10));
         m_fractional = 0;
-        
+
         if (std::isdigit(*endPtr))
         {
             throw std::out_of_range("Integer value is out of range.");
         }
-        
+
         // If the ending char is a period we can now parse the fractional part
         if (*endPtr == '.')
         {
             char* fracEndPtr = nullptr;
-            FractionalType fracTemp = __checkFracOverflow(strtoull(endPtr + 1, &fracEndPtr, 10));
+            FractionalType fracTemp =
+                __checkFracOverflow(strtoull(endPtr + 1, &fracEndPtr, 10));
             uint32_t fracLen = (fracEndPtr - endPtr) - 1;
-            
-            // DEBUG
-            //~ std::cout << "frac len: " << fracLen << std::endl;
+
             fracLen = fractional_decimal_digits - fracLen;
-            //~ std::cout << "invt len: " << fracLen << std::endl;
-            
+
             m_fractional = __checkFracOverflow(fracTemp * SCALE_VALUES[fracLen]);
             endPtr = fracEndPtr;
         }
-        // TODO: could calculate and return overall length
+        
+        // Calculate and return overall length
         return (endPtr - input);
     }
-    
+
     constexpr inline fixed operator-() const noexcept = delete;
     constexpr inline fixed operator!() const noexcept = delete;
     constexpr inline fixed operator~() const noexcept = delete;
     inline fixed& operator+=(const fixed& y) noexcept = delete;
     inline fixed& operator-=(const fixed& y) noexcept = delete;
     inline fixed& operator*=(const fixed& y) noexcept = delete;
-    inline fixed& operator/=(const fixed& y) noexcept = delete;    
-    
+    inline fixed& operator/=(const fixed& y) noexcept = delete;
+
     // Comparison operators
-    template <typename I, typename F>
-    friend constexpr inline bool operator==(const fixed<I, F>& x, const fixed<I, F>& y) noexcept;
-    
-    template <typename I, typename F>
-    friend constexpr inline bool operator!=(const fixed<I, F>& x, const fixed<I, F>& y) noexcept;
-    
-    template <typename I, typename F>
-    friend constexpr inline bool operator<(const fixed<I, F>& x, const fixed<I, F>& y) noexcept;
-    
-    template <typename I, typename F>
-    friend constexpr inline bool operator>(const fixed<I, F>& x, const fixed<I, F>& y) noexcept;
-    
-    template <typename I, typename F>
-    friend constexpr inline bool operator<=(const fixed<I, F>& x, const fixed<I, F>& y) noexcept;
-    
-    template <typename I, typename F>
-    friend constexpr inline bool operator>=(const fixed<I, F>& x, const fixed<I, F>& y) noexcept;
-    
+    template<typename I, typename F>
+    friend constexpr inline bool operator==(
+        const fixed<I, F>& x, const fixed<I, F>& y) noexcept;
+
+    template<typename I, typename F>
+    friend constexpr inline bool operator!=(
+        const fixed<I, F>& x, const fixed<I, F>& y) noexcept;
+
+    template<typename I, typename F>
+    friend constexpr inline bool operator<(
+        const fixed<I, F>& x, const fixed<I, F>& y) noexcept;
+
+    template<typename I, typename F>
+    friend constexpr inline bool operator>(
+        const fixed<I, F>& x, const fixed<I, F>& y) noexcept;
+
+    template<typename I, typename F>
+    friend constexpr inline bool operator<=(
+        const fixed<I, F>& x, const fixed<I, F>& y) noexcept;
+
+    template<typename I, typename F>
+    friend constexpr inline bool operator>=(
+        const fixed<I, F>& x, const fixed<I, F>& y) noexcept;
+
     // Output stream operator
-    template <typename I, typename F>
-    friend inline std::ostream& operator<<(std::ostream& os, const fixed<I, F>& rhs);
-    
+    template<typename I, typename F>
+    friend inline std::ostream& operator<<(
+        std::ostream& os, const fixed<I, F>& rhs);
+
 private:
 
     static inline IntegerType __checkIntOverflow(IntegerType integerVal)
@@ -167,19 +181,19 @@ private:
         {
             std::ostringstream msg;
             msg << "Integer value: " << integerVal << " exceeds maximum "
-                   "integer range of type (" << MAX_INTEGER_VALUE << ")!";
+                << "integer range of type (" << MAX_INTEGER_VALUE << ")!";
             throw std::out_of_range(msg.str());
         }
         return integerVal;
     }
-    
+
     static inline FractionalType __checkFracOverflow(FractionalType fractionalVal)
     {
         if (__unlikely(fractionalVal > MAX_FRACTIONAL_VALUE))
         {
             std::ostringstream msg;
             msg << "Fractional value: " << fractionalVal << " exceeds maximum "
-                   "fractional range of type (" << MAX_FRACTIONAL_VALUE << ")!";
+                << "fractional range of type (" << MAX_FRACTIONAL_VALUE << ")!";
             throw std::out_of_range(msg.str());
         }
         return fractionalVal;
@@ -187,7 +201,6 @@ private:
 
     IntegerType m_integer;
     FractionalType m_fractional;
-    
 };
 
 // Predefined types
@@ -211,14 +224,13 @@ using fixed_64_16 = fixed<int64_t, uint16_t>;
 using fixed_64_32 = fixed<int64_t, uint32_t>;
 using fixed_64_64 = fixed<int64_t, uint64_t>;
 
-
 // Precomputed scale value constants
-template <typename I, typename F>
-const uint64_t fixed<I, F>::SCALE_VALUES[20] =
+template<typename I, typename F>
+const uint64_t fixed<I, F>::SCALE_VALUES[20] = 
 {
-    /*  0 */ 1ULL, 
-    /*  1 */ 10ULL, 
-    /*  2 */ 100ULL, 
+    /*  0 */ 1ULL,
+    /*  1 */ 10ULL,
+    /*  2 */ 100ULL,
     /*  3 */ 1000ULL,
     /*  4 */ 10000ULL,
     /*  5 */ 100000ULL,
@@ -238,20 +250,23 @@ const uint64_t fixed<I, F>::SCALE_VALUES[20] =
     /* 19 */ 10000000000000000000ULL
 };
 
-template <typename I, typename F>
-constexpr inline bool operator==(const fixed<I, F>& x, const fixed<I, F>& y) noexcept
+template<typename I, typename F>
+constexpr inline bool operator==(
+    const fixed<I, F>& x, const fixed<I, F>& y) noexcept
 {
     return (x.m_integer == y.m_integer && x.m_fractional == y.m_fractional);
 }
 
-template <typename I, typename F>
-constexpr inline bool operator!=(const fixed<I, F>& x, const fixed<I, F>& y) noexcept
+template<typename I, typename F>
+constexpr inline bool operator!=(
+    const fixed<I, F>& x, const fixed<I, F>& y) noexcept
 {
     return (! (x == y));
 }
 
-template <typename I, typename F>
-constexpr inline bool operator<(const fixed<I, F>& x, const fixed<I, F>& y) noexcept
+template<typename I, typename F>
+constexpr inline bool operator<(
+    const fixed<I, F>& x, const fixed<I, F>& y) noexcept
 {
     if (x.m_integer == y.m_integer)
     {
@@ -261,12 +276,13 @@ constexpr inline bool operator<(const fixed<I, F>& x, const fixed<I, F>& y) noex
     {
         return (x.m_integer < y.m_integer);
     }
-    
-    return false;    
+
+    return false;
 }
 
-template <typename I, typename F>
-constexpr inline bool operator>(const fixed<I, F>& x, const fixed<I, F>& y) noexcept
+template<typename I, typename F>
+constexpr inline bool operator>(
+    const fixed<I, F>& x, const fixed<I, F>& y) noexcept
 {
     if (x.m_integer == y.m_integer)
     {
@@ -276,12 +292,13 @@ constexpr inline bool operator>(const fixed<I, F>& x, const fixed<I, F>& y) noex
     {
         return (x.m_integer > y.m_integer);
     }
-    
-    return false;    
+
+    return false;
 }
 
-template <typename I, typename F>
-constexpr inline bool operator<=(const fixed<I, F>& x, const fixed<I, F>& y) noexcept
+template<typename I, typename F>
+constexpr inline bool operator<=(
+    const fixed<I, F>& x, const fixed<I, F>& y) noexcept
 {
     if (x.m_integer == y.m_integer)
     {
@@ -291,12 +308,13 @@ constexpr inline bool operator<=(const fixed<I, F>& x, const fixed<I, F>& y) noe
     {
         return (x.m_integer < y.m_integer);
     }
-    
-    return false;    
+
+    return false;
 }
 
-template <typename I, typename F>
-constexpr inline bool operator>=(const fixed<I, F>& x, const fixed<I, F>& y) noexcept
+template<typename I, typename F>
+constexpr inline bool operator>=(
+    const fixed<I, F>& x, const fixed<I, F>& y) noexcept
 {
     if (x.m_integer == y.m_integer)
     {
@@ -306,34 +324,37 @@ constexpr inline bool operator>=(const fixed<I, F>& x, const fixed<I, F>& y) noe
     {
         return (x.m_integer > y.m_integer);
     }
-    
+
     return false;
 }
 
 // Addition -- not yet supported
-template <typename I, typename F>
-constexpr inline fixed<I, F> operator+(const fixed<I, F>& x, const fixed<I, F>& y) noexcept = delete;
+template<typename I, typename F>
+constexpr inline fixed<I, F> operator+(
+    const fixed<I, F>& x, const fixed<I, F>& y) noexcept = delete;
 
 // Subtraction -- not yet supported
-template <typename I, typename F>
-constexpr inline fixed<I, F> operator-(const fixed<I, F>& x, const fixed<I, F>& y) noexcept = delete;
+template<typename I, typename F>
+constexpr inline fixed<I, F> operator-(
+    const fixed<I, F>& x, const fixed<I, F>& y) noexcept = delete;
 
 // Multiplication
-template <typename I, typename F>
-constexpr inline fixed<I, F> operator*(const fixed<I, F>& x, const fixed<I, F>& y) noexcept = delete;
+template<typename I, typename F>
+constexpr inline fixed<I, F> operator*(
+    const fixed<I, F>& x, const fixed<I, F>& y) noexcept = delete;
 
 // Division -- not yet supported
-template <typename I, typename F>
-constexpr inline fixed<I, F> operator/(const fixed<I, F>& x, const fixed<I, F>& y) noexcept = delete;
+template<typename I, typename F>
+constexpr inline fixed<I, F> operator/(
+    const fixed<I, F>& x, const fixed<I, F>& y) noexcept = delete;
 
 // Stream output
-template <typename I, typename F>
+template<typename I, typename F>
 inline std::ostream& operator<<(std::ostream& os, const fixed<I, F>& rhs)
 {
-    return os << std::fixed << rhs.m_integer << "." 
-              << std::setw(fixed<I, F>::fractional_decimal_digits) << std::setfill('0') 
-              << rhs.m_fractional;
+    return os << std::fixed << rhs.m_integer << "."
+              << std::setw(fixed<I, F>::fractional_decimal_digits)
+              << std::setfill('0') << rhs.m_fractional;
 }
 
-
-#endif // FIXED_H_
+#endif  // FIXED_H_
diff --git a/software/fixed/fixed_test.cc b/software/fixed/fixed_test.cc
index aa56bc4..0a6d803 100644
--- a/software/fixed/fixed_test.cc
+++ b/software/fixed/fixed_test.cc
@@ -1,100 +1,48 @@
-#include <cmath>
+
 #include <cstdint>
 #include <limits>
-#include <iomanip>
-#include <iostream>
-#include <stdexcept>
+
+#define BOOST_TEST_MAIN  1
+#include <boost/test/unit_test.hpp>
 
 #include "fixed.h"
-#include "int128.h"
 
-// g++ fixed_test.cc -o fixed_test
-int main(int argc, char** argv)
+BOOST_AUTO_TEST_CASE(t0)
 {
-    std::cout << "Fixed Type Test Util\n" << std::endl;
-
-    fixed_64_64 foobar;
-    std::cout << "Type size: " << sizeof(fixed_64_64) << std::endl;
-    
-    std::cout << "Integer decimal digits: " << fixed_64_64::integer_decimal_digits << std::endl;
-    std::cout << "Fractional decimal digits: " << fixed_64_64::fractional_decimal_digits << std::endl;
-    
-    std::cout << "Max integer value: " << fixed_64_64::MAX_INTEGER_VALUE << std::endl;
-    
-    std::cout << "Max fractional value: " << fixed_64_64::MAX_FRACTIONAL_VALUE << std::endl;
-    
-    std::cout << std::endl;
-    std::cout << "Value: " << foobar << std::endl;
-    
-    fixed_64_64 quxbar(3, 1415926353);
-    std::cout << "Value: " << quxbar << std::endl;
-    
-    fixed_64_64 intMax(999999999999999999ULL);
-    std::cout << "Value: " << intMax << std::endl;
-    
-    try
-    {
-        fixed_64_64 intOverflow(1999999999999999999ULL);
-        std::cout << "Value: " << intMax << std::endl;
-    }
-    catch (const std::out_of_range& excep)
-    {
-        std::cout << "Integer overflow caught" << std::endl;
-    }
-    
-    fixed_64_64 fracMax(0, 9999999999999999999ULL);
-    std::cout << "Value: " << fracMax << std::endl;
-    
-    try
-    {
-        fixed_64_64 fracOverflow(0, 10000000000000000001ULL);
-    }
-    catch (const std::out_of_range& excep)
-    {
-        std::cout << "Fractional overflow caught" << std::endl;
-    }
-    
-    
-    fixed_64_64 value1;
-    fixed_64_64 value2;
-    const char* strVal = "100.1";
-    value1.parse(strVal);
-    std::cout << "String value: " << strVal << std::endl;
-    std::cout << "Parsed value: " << value1 << std::endl;
-    
-    strVal = "100";
-    value2.parse(strVal);
-    std::cout << "String value: " << strVal << std::endl;
-    std::cout << "Parsed value: " << value2 << std::endl;
-    
-    std::cout << value1 << " == " << value2 << " --> " << (value1 == value2) << std::endl;
-    std::cout << value1 << " != " << value2 << " --> " << (value1 != value2) << std::endl;
-    std::cout << value1 << " > " << value2 << " --> " << (value1 > value2) << std::endl;
-    std::cout << value1 << " < " << value2 << " --> " << (value1 < value2) << std::endl;    
-    std::cout << value1 << " >= " << value2 << " --> " << (value1 >= value2) << std::endl;
-    std::cout << value1 << " <= " << value2 << " --> " << (value1 <= value2) << std::endl;
-    
-    //~ double foo = std::pow(10, 18);
-    //~ std::cout << "Foo: " << std::fixed << std::setprecision(0) << foo << std::endl;
-    //~ std::cout << "Foo: " << std::fixed << std::setprecision(0) << (static_cast<uint64_t>(foo) - 1) << std::endl;
-    
-    uint128_t big = 1098298217598174ULL;
-    std::cout << "BIG INT: " << big << std::endl;
-    big *= 1098982694765;
-    std::cout << "BIGGER INT: " << big << std::endl;
-    
-    std::cout << "INT128T MAX: " << std::numeric_limits<int128_t>::max() << std::endl;
-    std::cout << "UINT128T MAX: " << std::numeric_limits<uint128_t>::max() << std::endl;
-    
-    strVal = "-1207010734831637608463359110";
-    int128_t s128Val = strtoll_128(strVal, nullptr, 0);
-    std::cout << "String value: " << strVal << std::endl;
-    std::cout << "Parsed value: " << s128Val << std::endl;
-    
-    strVal = "991207010734831637608463359110888";
-    uint128_t u128Val = strtoull_128(strVal, nullptr, 0);
-    std::cout << "String value: " << strVal << std::endl;
-    std::cout << "Parsed value: " << u128Val << std::endl;
-    
-    return 0;
+    // Check overall type sizes
+    fixed_8_8  f_8_8;
+    fixed_8_32 f_8_32;
+    fixed_8_16 f_8_16;
+    fixed_8_64 f_8_64;
+    BOOST_CHECK(sizeof(f_8_8)  == 2);
+    BOOST_CHECK(sizeof(f_8_16) == 4);
+    BOOST_CHECK(sizeof(f_8_32) == 8);
+    BOOST_CHECK(sizeof(f_8_64) == 16);
+    
+    fixed_16_8  f_16_8;
+    fixed_16_16 f_16_16;
+    fixed_16_32 f_16_32;
+    fixed_16_64 f_16_64;
+    BOOST_CHECK(sizeof(f_16_8)  == 4);
+    BOOST_CHECK(sizeof(f_16_16) == 4);
+    BOOST_CHECK(sizeof(f_16_32) == 8);
+    BOOST_CHECK(sizeof(f_16_64) == 16);
+    
+    fixed_32_8  f_32_8;
+    fixed_32_16 f_32_16;
+    fixed_32_32 f_32_32;
+    fixed_32_64 f_32_64;
+    BOOST_CHECK(sizeof(f_32_8)  == 8);
+    BOOST_CHECK(sizeof(f_32_16) == 8);
+    BOOST_CHECK(sizeof(f_32_32) == 8);
+    BOOST_CHECK(sizeof(f_32_64) == 16);
+    
+    fixed_64_8  f_64_8;
+    fixed_64_16 f_64_16;
+    fixed_64_32 f_64_32;
+    fixed_64_64 f_64_64;
+    BOOST_CHECK(sizeof(f_64_8)  == 16);
+    BOOST_CHECK(sizeof(f_64_16) == 16);
+    BOOST_CHECK(sizeof(f_64_32) == 16);
+    BOOST_CHECK(sizeof(f_64_64) == 16);
 }
diff --git a/software/fixed/fixed_util.cc b/software/fixed/fixed_util.cc
new file mode 100644
index 0000000..10108cf
--- /dev/null
+++ b/software/fixed/fixed_util.cc
@@ -0,0 +1,101 @@
+#include <cmath>
+#include <cstdint>
+#include <limits>
+#include <iomanip>
+#include <iostream>
+#include <stdexcept>
+
+#include "fixed.h"
+#include "int128.h"
+
+// g++ fixed_test.cc -o fixed_test
+int main(int argc, char** argv)
+{
+    std::cout << "Fixed Type Test Util\n" << std::endl;
+
+    fixed_64_64 foobar;
+    std::cout << "Type size: " << sizeof(fixed_64_64) << std::endl;
+    
+    std::cout << "Integer decimal digits: " << fixed_64_64::integer_decimal_digits << std::endl;
+    std::cout << "Fractional decimal digits: " << fixed_64_64::fractional_decimal_digits << std::endl;
+    
+    std::cout << "Max integer value: " << fixed_64_64::MAX_INTEGER_VALUE << std::endl;
+    
+    std::cout << "Max fractional value: " << fixed_64_64::MAX_FRACTIONAL_VALUE << std::endl;
+    
+    std::cout << std::endl;
+    std::cout << "Value: " << foobar << std::endl;
+    
+    fixed_64_64 quxbar(3, 1415926353);
+    std::cout << "Value: " << quxbar << std::endl;
+    
+    fixed_64_64 intMax(999999999999999999ULL);
+    std::cout << "Value: " << intMax << std::endl;
+    
+    try
+    {
+        fixed_64_64 intOverflow(1999999999999999999ULL);
+        std::cout << "Value: " << intMax << std::endl;
+    }
+    catch (const std::out_of_range& excep)
+    {
+        std::cout << "Integer overflow caught" << std::endl;
+    }
+    
+    fixed_64_64 fracMax(0, 9999999999999999999ULL);
+    std::cout << "Value: " << fracMax << std::endl;
+    
+    try
+    {
+        fixed_64_64 fracOverflow(0, 10000000000000000001ULL);
+    }
+    catch (const std::out_of_range& excep)
+    {
+        std::cout << "Fractional overflow caught" << std::endl;
+    }
+    
+    
+    fixed_64_64 value1;
+    fixed_64_64 value2;
+    const char* strVal = "100.1";
+    value1.parse(strVal);
+    std::cout << "String value: " << strVal << std::endl;
+    std::cout << "Parsed value: " << value1 << std::endl;
+    
+    strVal = "100";
+    value2.parse(strVal);
+    std::cout << "String value: " << strVal << std::endl;
+    std::cout << "Parsed value: " << value2 << std::endl;
+    
+    std::cout << value1 << " == " << value2 << " --> " << (value1 == value2) << std::endl;
+    std::cout << value1 << " != " << value2 << " --> " << (value1 != value2) << std::endl;
+    std::cout << value1 << " > " << value2 << " --> " << (value1 > value2) << std::endl;
+    std::cout << value1 << " < " << value2 << " --> " << (value1 < value2) << std::endl;    
+    std::cout << value1 << " >= " << value2 << " --> " << (value1 >= value2) << std::endl;
+    std::cout << value1 << " <= " << value2 << " --> " << (value1 <= value2) << std::endl;
+    
+    //~ double foo = std::pow(10, 18);
+    //~ std::cout << "Foo: " << std::fixed << std::setprecision(0) << foo << std::endl;
+    //~ std::cout << "Foo: " << std::fixed << std::setprecision(0) << (static_cast<uint64_t>(foo) - 1) << std::endl;
+    
+    uint128_t big = 1098298217598174ULL;
+    std::cout << "BIG INT: " << big << std::endl;
+    big *= 1098982694765;
+    std::cout << "BIGGER INT: " << big << std::endl;
+    
+    std::cout << "INT128T MAX: " << std::numeric_limits<int128_t>::max() << std::endl;
+    std::cout << "UINT128T MAX: " << std::numeric_limits<uint128_t>::max() << std::endl;
+    
+    strVal = "-1207010734831637608463359110";
+    int128_t s128Val = strtoll_128(strVal, nullptr, 0);
+    std::cout << "String value: " << strVal << std::endl;
+    std::cout << "Parsed value: " << s128Val << std::endl;
+    
+    //~ strVal = "991207010734831637608463359110888";
+    strVal = "340282366920938463463374607431768211456";
+    uint128_t u128Val = strtoull_128(strVal, nullptr, 0);
+    std::cout << "String value: " << strVal << std::endl;
+    std::cout << "Parsed value: " << u128Val << std::endl;
+    
+    return 0;
+}
diff --git a/software/fixed/int128.h b/software/fixed/int128.h
index c3cc606..e31bc36 100644
--- a/software/fixed/int128.h
+++ b/software/fixed/int128.h
@@ -72,6 +72,7 @@ constexpr uint128_t max_tab[]
     std::numeric_limits<uint128_t>::max() /  7,
     std::numeric_limits<uint128_t>::max() /  8,
     std::numeric_limits<uint128_t>::max() /  9,
+    std::numeric_limits<uint128_t>::max() / 10,
     std::numeric_limits<uint128_t>::max() / 11,
     std::numeric_limits<uint128_t>::max() / 12,
     std::numeric_limits<uint128_t>::max() / 13,
@@ -109,6 +110,7 @@ constexpr uint32_t rem_tab[]
     std::numeric_limits<uint128_t>::max() %  7,
     std::numeric_limits<uint128_t>::max() %  8,
     std::numeric_limits<uint128_t>::max() %  9,
+    std::numeric_limits<uint128_t>::max() % 10,
     std::numeric_limits<uint128_t>::max() % 11,
     std::numeric_limits<uint128_t>::max() % 12,
     std::numeric_limits<uint128_t>::max() % 13,
@@ -429,4 +431,234 @@ noconv:
     return 0;
 }
 
+
+int128_t strtoll_128_b10opt(const char* nptr, char** endptr, int base=10)
+{
+    bool negative = false;
+    uint128_t cutoff = 0;
+    uint32_t cutlim = 0;
+    int128_t value = 0;
+    const char* ptr;
+    unsigned char chr;
+    const char *save, *end;
+    bool overflow = false;
+
+    // Validate the base parameter
+#if 0
+    if (base < 0 || base == 1 || base > 36)
+    {
+        std::ostringstream msg;
+        msg << "Base value \"" << base << "\" is invalid; base must be "
+            << "between 2-36 (inclusive).";
+        throw std::out_of_range(msg.str());
+    }
+#endif
+    
+    save = ptr = nptr;
+    
+    // Skip any leading whitespace
+    while (std::isspace(*ptr))
+    {
+        ++ptr;
+    }
+    
+    // Check for end of string
+    if (__builtin_expect((*ptr == '\0'), 0))
+    {
+        goto noconv;
+    }
+    
+    // Parse -/+
+    if (*ptr == '-')
+    {
+        negative = true;
+        ++ptr;
+    }
+    else if (*ptr == '+')
+    {
+        ++ptr;
+    }
+    
+    // Save start of digits
+    save = ptr;
+    end = nullptr;
+    
+    cutoff = max_tab[8];    // base 10
+    cutlim = rem_tab[8];
+    
+    // Iterate over the characters
+    chr = *ptr;
+    for (; chr != '\0'; chr = *++ptr)
+    {
+        if (ptr == end)
+        {
+            break;
+        }
+        
+        if (chr >= '0' && chr <= '9')
+        {
+            chr -= '0';
+        }
+        else
+        {
+            break;
+        }
+
+        if (value > cutoff || (value == cutoff && chr > cutlim))
+        {
+            overflow = true;
+            break;
+        }
+        else
+        {   
+            value *= static_cast<uint128_t>(10);
+            value += (int)chr;
+        }
+    }
+    
+    // Check if no conversion was done
+    if (ptr == save)
+    {
+        goto noconv;
+    }
+    
+    // Store end if requested
+    if (endptr != nullptr)
+    {
+        *endptr = const_cast<char*>(ptr);
+    }
+        
+    // Check for overflow
+    if (__builtin_expect((overflow), 0))
+    {
+        std::ostringstream msg;
+        msg << "Overflow detected at input offset " << (ptr - nptr);
+        throw std::overflow_error(msg.str());
+    }
+    
+    // Regular return path
+    return negative ? -value : value;
+    
+noconv:
+
+    if (endptr != nullptr)
+    {
+        *endptr = const_cast<char*>(nptr);
+    }
+
+    return 0;
+}
+
+
+uint128_t strtoull_128_b10opt(const char* nptr, char** endptr, int base=10)
+{
+    uint128_t cutoff = 0;
+    uint32_t cutlim = 0;
+    uint128_t value = 0;
+    const char* ptr;
+    unsigned char chr;
+    const char *save, *end;
+    bool overflow = false;
+
+    // Validate the base parameter
+#if 0
+    if (base < 0 || base == 1 || base > 36)
+    {
+        std::ostringstream msg;
+        msg << "Base value \"" << base << "\" is invalid; base must be "
+            << "between 2-36 (inclusive).";
+        throw std::out_of_range(msg.str());
+    }
+#endif
+    
+    save = ptr = nptr;
+    
+    // Skip any leading whitespace
+    while (std::isspace(*ptr))
+    {
+        ++ptr;
+    }
+    
+    // Check for end of string
+    if (__builtin_expect((*ptr == '\0'), 0))
+    {
+        goto noconv;
+    }
+    
+    // Parse -/+
+    if (*ptr == '-' || *ptr == '+')
+    {
+        ++ptr;
+    }
+    
+    // Save start of digits
+    save = ptr;
+    end = nullptr;
+    
+    cutoff = max_tab[8];    // base 10
+    cutlim = rem_tab[8];
+    
+    // Iterate over the characters
+    chr = *ptr;
+    for (; chr != '\0'; chr = *++ptr)
+    {
+        if (ptr == end)
+        {
+            break;
+        }
+        
+        if (chr >= '0' && chr <= '9')
+        {
+            chr -= '0';
+        }
+        else
+        {
+            break;
+        }
+        
+        if (value > cutoff || (value == cutoff && chr > cutlim))
+        {
+            overflow = true;
+            break;
+        }
+        else
+        {   
+            value *= static_cast<uint128_t>(10);
+            value += (int)chr;
+        }
+    }
+    
+    // Check if no conversion was done
+    if (ptr == save)
+    {
+        goto noconv;
+    }
+    
+    // Store end if requested
+    if (endptr != nullptr)
+    {
+        *endptr = const_cast<char*>(ptr);
+    }
+        
+    // Check for overflow
+    if (__builtin_expect((overflow), 0))
+    {
+        std::ostringstream msg;
+        msg << "Overflow detected at input offset " << (ptr - nptr);
+        throw std::overflow_error(msg.str());
+    }
+    
+    // Regular return path
+    return value;
+    
+noconv:
+
+    if (endptr != nullptr)
+    {
+        *endptr = const_cast<char*>(nptr);
+    }
+
+    return 0;
+}
+
 #endif
diff --git a/software/fixed/int128_test.cc b/software/fixed/int128_test.cc
new file mode 100644
index 0000000..2201100
--- /dev/null
+++ b/software/fixed/int128_test.cc
@@ -0,0 +1,21 @@
+
+#include <cstdint>
+#include <limits>
+
+#define BOOST_TEST_MAIN  1
+#include <boost/test/unit_test.hpp>
+
+#include "int128.h"
+
+BOOST_AUTO_TEST_CASE(t0)
+{
+    uint32_t foo;
+    BOOST_CHECK(sizeof(foo) == 4);
+}
+
+BOOST_AUTO_TEST_CASE(t1)
+{
+    uint32_t foo;
+    BOOST_CHECK(sizeof(foo) == 8);
+}
+
