Revision c7e0510c
Added by David Sorber over 4 years ago
| software/fixed/.clang-format | ||
|---|---|---|
|
---
|
||
|
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
|
||
|
...
|
||
|
|
||
| software/fixed/CMakeLists.txt | ||
|---|---|---|
|
|
||
|
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)
|
||
|
|
||
| software/fixed/fixed.h | ||
|---|---|---|
|
|
||
|
#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;
|
||
| ... | ... | |
|
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)
|
||
|
{
|
||
| ... | ... | |
|
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)
|
||
| ... | ... | |
|
{
|
||
|
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;
|
||
| ... | ... | |
|
|
||
|
IntegerType m_integer;
|
||
|
FractionalType m_fractional;
|
||
|
|
||
|
};
|
||
|
|
||
|
// Predefined types
|
||
| ... | ... | |
|
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,
|
||
| ... | ... | |
|
/* 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)
|
||
|
{
|
||
| ... | ... | |
|
{
|
||
|
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)
|
||
|
{
|
||
| ... | ... | |
|
{
|
||
|
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)
|
||
|
{
|
||
| ... | ... | |
|
{
|
||
|
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)
|
||
|
{
|
||
| ... | ... | |
|
{
|
||
|
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_
|
||
| software/fixed/fixed_test.cc | ||
|---|---|---|
|
#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);
|
||
|
}
|
||
| software/fixed/fixed_util.cc | ||
|---|---|---|
|
#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;
|
||
|
}
|
||
| software/fixed/int128.h | ||
|---|---|---|
|
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,
|
||
| ... | ... | |
|
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,
|
||
| ... | ... | |
|
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
|
||
| software/fixed/int128_test.cc | ||
|---|---|---|
|
|
||
|
#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);
|
||
|
}
|
||
|
|
||
Fix minor bug in int128.h. Also add initial unit tests.