Repository: ckormanyos/wide-integer Branch: master Commit: 3922df20c64c Files: 95 Total size: 1.3 MB Directory structure: gitextract_cm9ct4p2/ ├── .clang-tidy ├── .gcov/ │ └── make/ │ ├── make_gcov_01_generic.gmk │ ├── make_gcov_02_files.gmk │ └── make_gcov_03_flags.gmk ├── .github/ │ ├── toolchains/ │ │ └── gcc.cmake │ └── workflows/ │ ├── CodeQL.yml │ ├── wide_integer.yml │ ├── wide_integer_codecov.yml │ ├── wide_integer_fuzzing.yml │ └── wide_integer_sonar.yml ├── .gitignore ├── .props/ │ └── Directory.Build.props ├── .tidy/ │ └── make/ │ ├── make_tidy_01_generic.gmk │ ├── make_tidy_02_files.gmk │ └── make_tidy_03_flags.gmk ├── CMakeLists.txt ├── LICENSE_1_0.txt ├── Makefile ├── README.md ├── boost/ │ └── multiprecision/ │ └── uintwide_t_backend.hpp ├── codecov.yml ├── examples/ │ ├── CMakeLists.txt │ ├── build/ │ │ └── test_examples.sh │ ├── example000_numeric_limits.cpp │ ├── example000a_builtin_convert.cpp │ ├── example001_mul_div.cpp │ ├── example001a_div_mod.cpp │ ├── example002_shl_shr.cpp │ ├── example003_sqrt.cpp │ ├── example003a_cbrt.cpp │ ├── example004_rootk_pow.cpp │ ├── example005_powm.cpp │ ├── example005a_pow_factors_of_p99.cpp │ ├── example006_gcd.cpp │ ├── example007_random_generator.cpp │ ├── example008_miller_rabin_prime.cpp │ ├── example008a_miller_rabin_prime.cpp │ ├── example008b_solovay_strassen_prime.cpp │ ├── example009_timed_mul.cpp │ ├── example009a_timed_mul_4_by_4.cpp │ ├── example009b_timed_mul_8_by_8.cpp │ ├── example010_uint48_t.cpp │ ├── example011_uint24_t.cpp │ ├── example012_rsa_crypto.cpp │ ├── example013_ecdsa_sign_verify.cpp │ ├── example014_pi_spigot_wide.cpp │ └── example_uintwide_t.h ├── math/ │ └── wide_integer/ │ ├── cpp.hint │ └── uintwide_t.h ├── run_fuzzing.sh ├── sonar-project.properties ├── target/ │ ├── build/ │ │ └── test_examples_emulator.gdb │ └── micros/ │ └── stm32f429/ │ └── make/ │ ├── single/ │ │ └── crt.cpp │ └── stm32f429.ld ├── test/ │ ├── CMakeLists.txt │ ├── coverity.c │ ├── fuzzing/ │ │ ├── test_fuzzing_add.cpp │ │ ├── test_fuzzing_div.cpp │ │ ├── test_fuzzing_div_versus_cppalliance_int128.cpp │ │ ├── test_fuzzing_mul.cpp │ │ ├── test_fuzzing_powm.cpp │ │ ├── test_fuzzing_prime.cpp │ │ ├── test_fuzzing_sdiv.cpp │ │ ├── test_fuzzing_sqrt.cpp │ │ └── test_fuzzing_sub.cpp │ ├── parallel_for.h │ ├── stopwatch.h │ ├── test.cpp │ ├── test.hpp │ ├── test_arithmetic.hpp │ ├── test_uintwide_t.h │ ├── test_uintwide_t_boost_backend.cpp │ ├── test_uintwide_t_boost_backend_via_test_arithmetic.cpp │ ├── test_uintwide_t_edge_cases.cpp │ ├── test_uintwide_t_examples.cpp │ ├── test_uintwide_t_float_convert.cpp │ ├── test_uintwide_t_int_convert.cpp │ ├── test_uintwide_t_n_base.cpp │ ├── test_uintwide_t_n_base.h │ ├── test_uintwide_t_n_binary_ops_base.cpp │ ├── test_uintwide_t_n_binary_ops_base.h │ ├── test_uintwide_t_n_binary_ops_mul_div_4_by_4_template.h │ ├── test_uintwide_t_n_binary_ops_mul_n_by_m_template.h │ ├── test_uintwide_t_n_binary_ops_template.h │ ├── test_uintwide_t_n_binary_ops_template_signed.h │ ├── test_uintwide_t_n_number_theory_funcs_template.h │ ├── test_uintwide_t_spot_values.cpp │ └── test_uintwide_t_xtra_from_issue_335.cpp ├── util/ │ └── utility/ │ └── util_pseudorandom_time_point_seed.h ├── wide_integer.sln ├── wide_integer.vcxproj ├── wide_integer.vcxproj.filters ├── wide_integer_vs2022.sln ├── wide_integer_vs2022.vcxproj └── wide_integer_vs2022.vcxproj.filters ================================================ FILE CONTENTS ================================================ ================================================ FILE: .clang-tidy ================================================ --- Checks: > *, -altera-struct-pack-align, -altera-unroll-loops, -fuchsia-*, -llvmlibc-* WarningsAsErrors: '*' HeaderFilterRegex: '.*' FormatStyle: none User: john CheckOptions: - key: cert-dcl16-c.NewSuffixes value: 'L;LL;LU;LLU' - key: cppcoreguidelines-non-private-member-variables-in-classes.IgnoreClassesWithAllMemberVariablesBeingPublic value: '1' - key: google-readability-braces-around-statements.ShortStatementLines value: '1' - key: google-readability-function-size.StatementThreshold value: '800' - key: google-readability-namespace-comments.ShortNamespaceLines value: '10' - key: google-readability-namespace-comments.SpacesBeforeComments value: '2' - key: modernize-loop-convert.MaxCopySize value: '16' - key: modernize-loop-convert.MinConfidence value: reasonable - key: modernize-loop-convert.NamingStyle value: CamelCase - key: modernize-pass-by-value.IncludeStyle value: llvm - key: modernize-replace-auto-ptr.IncludeStyle value: llvm - key: modernize-use-nullptr.NullMacros value: 'NULL' # because _impl isn't technically lower_case # - key: readability-identifier-naming.NamespaceCase # value: lower_case - key: readability-identifier-naming.InlineNamespaceCase value: lower_case - key: readability-identifier-naming.EnumConstantCase value: lower_case # - key: readability-identifier-naming.ConstexprVariableCase # value: lower_case - key: readability-identifier-naming.ConstantMemberCase value: lower_case - key: readability-identifier-naming.PrivateMemberCase value: lower_case - key: readability-identifier-naming.ProtectedMemberCase value: lower_case - key: readability-identifier-naming.PublicMemberCase value: lower_case - key: readability-identifier-naming.MemberCase value: lower_case # - key: readability-identifier-naming.ClassConstantCase # value: lower_case # - key: readability-identifier-naming.ClassMemberCase # value: lower_case # - key: readability-identifier-naming.GlobalConstantCase # value: lower_case - key: readability-identifier-naming.GlobalConstantPointerCase value: lower_case - key: readability-identifier-naming.GlobalPointerCase value: lower_case # - key: readability-identifier-naming.GlobalVariableCase # value: lower_case - key: readability-identifier-naming.LocalConstantCase value: lower_case - key: readability-identifier-naming.LocalConstantPointerCase value: lower_case - key: readability-identifier-naming.LocalPointerCase value: lower_case - key: readability-identifier-naming.LocalVariableCase value: lower_case - key: readability-identifier-naming.StaticConstantCase value: lower_case - key: readability-identifier-naming.StaticVariableCase value: lower_case # - key: readability-identifier-naming.ConstantCase # value: lower_case # - key: readability-identifier-naming.VariableCase # value: lower_case - key: readability-identifier-naming.ConstantParameterCase value: lower_case - key: readability-identifier-naming.ParameterPackCase value: lower_case - key: readability-identifier-naming.ParameterCase value: lower_case - key: readability-identifier-naming.PointerParameterCase value: lower_case - key: readability-identifier-naming.ConstantPointerParameterCase value: lower_case - key: readability-identifier-naming.AbstractClassCase value: lower_case - key: readability-identifier-naming.StructCase value: lower_case - key: readability-identifier-naming.ClassCase value: lower_case - key: readability-identifier-naming.UnionCase value: lower_case - key: readability-identifier-naming.EnumCase value: lower_case - key: readability-identifier-naming.GlobalFunctionCase value: lower_case # - key: readability-identifier-naming.ConstexprFunctionCase # value: lower_case - key: readability-identifier-naming.FunctionCase value: lower_case # - key: readability-identifier-naming.ConstexprMethodCase # value: lower_case - key: readability-identifier-naming.VirtualMethodCase value: lower_case # - key: readability-identifier-naming.ClassMethodCase # value: lower_case - key: readability-identifier-naming.PrivateMethodCase value: lower_case - key: readability-identifier-naming.ProtectedMethodCase value: lower_case - key: readability-identifier-naming.PublicMethodCase value: lower_case - key: readability-identifier-naming.MethodCase value: lower_case - key: readability-identifier-naming.TypedefCase value: lower_case # https://bugs.llvm.org/show_bug.cgi?id=46752 # - key: readability-identifier-naming.TypeTemplateParameterCase # value: CamelCase - key: readability-identifier-naming.ValueTemplateParameterCase value: CamelCase - key: readability-identifier-naming.TemplateTemplateParameterCase value: CamelCase # https://bugs.llvm.org/show_bug.cgi?id=46752 # - key: readability-identifier-naming.TemplateParameterCase # value: CamelCase - key: readability-identifier-naming.TypeAliasCase value: lower_case - key: readability-identifier-naming.MacroDefinitionCase value: UPPER_CASE - key: readability-identifier-naming.ObjcIvarCase value: lower_case - key: readability-identifier-naming.NamespacePrefix value: '' - key: readability-identifier-naming.InlineNamespacePrefix value: '' - key: readability-identifier-naming.EnumConstantPrefix value: '' - key: readability-identifier-naming.ConstexprVariablePrefix value: '' - key: readability-identifier-naming.ConstantMemberPrefix value: '' - key: readability-identifier-naming.PrivateMemberPrefix value: '_' - key: readability-identifier-naming.ProtectedMemberPrefix value: '_' - key: readability-identifier-naming.PublicMemberPrefix value: '' - key: readability-identifier-naming.MemberPrefix value: '' - key: readability-identifier-naming.ClassConstantPrefix value: '' - key: readability-identifier-naming.ClassMemberPrefix value: '' - key: readability-identifier-naming.GlobalConstantPrefix value: '' - key: readability-identifier-naming.GlobalConstantPointerPrefix value: '' - key: readability-identifier-naming.GlobalPointerPrefix value: '' - key: readability-identifier-naming.GlobalVariablePrefix value: '' - key: readability-identifier-naming.LocalConstantPrefix value: '' - key: readability-identifier-naming.LocalConstantPointerPrefix value: '' - key: readability-identifier-naming.LocalPointerPrefix value: '' - key: readability-identifier-naming.LocalVariablePrefix value: '' - key: readability-identifier-naming.StaticConstantPrefix value: '' - key: readability-identifier-naming.StaticVariablePrefix value: '' - key: readability-identifier-naming.ConstantPrefix value: '' - key: readability-identifier-naming.VariablePrefix value: '' - key: readability-identifier-naming.ConstantParameterPrefix value: '' - key: readability-identifier-naming.ParameterPackPrefix value: '' - key: readability-identifier-naming.ParameterPrefix value: '' - key: readability-identifier-naming.PointerParameterPrefix value: '' - key: readability-identifier-naming.ConstantPointerParameterPrefix value: '' - key: readability-identifier-naming.AbstractClassPrefix value: '' - key: readability-identifier-naming.StructPrefix value: '' - key: readability-identifier-naming.ClassPrefix value: '' - key: readability-identifier-naming.UnionPrefix value: '' - key: readability-identifier-naming.EnumPrefix value: '' - key: readability-identifier-naming.GlobalFunctionPrefix value: '' - key: readability-identifier-naming.ConstexprFunctionPrefix value: '' - key: readability-identifier-naming.FunctionPrefix value: '' - key: readability-identifier-naming.ConstexprMethodPrefix value: '' - key: readability-identifier-naming.VirtualMethodPrefix value: '' - key: readability-identifier-naming.ClassMethodPrefix value: '' - key: readability-identifier-naming.PrivateMethodPrefix value: '' - key: readability-identifier-naming.ProtectedMethodPrefix value: '' - key: readability-identifier-naming.PublicMethodPrefix value: '' - key: readability-identifier-naming.MethodPrefix value: '' - key: readability-identifier-naming.TypedefPrefix value: '' - key: readability-identifier-naming.TypeTemplateParameterPrefix value: '' - key: readability-identifier-naming.ValueTemplateParameterPrefix value: '' - key: readability-identifier-naming.TemplateTemplateParameterPrefix value: '' - key: readability-identifier-naming.TemplateParameterPrefix value: '' - key: readability-identifier-naming.TypeAliasPrefix value: '' - key: readability-identifier-naming.MacroDefinitionPrefix value: '' - key: readability-identifier-naming.ObjcIvarPrefix value: '' - key: readability-identifier-naming.NamespaceSuffix value: '' - key: readability-identifier-naming.InlineNamespaceSuffix value: '' - key: readability-identifier-naming.EnumConstantSuffix value: '' - key: readability-identifier-naming.ConstexprVariableSuffix value: '' - key: readability-identifier-naming.ConstantMemberSuffix value: '' - key: readability-identifier-naming.PrivateMemberSuffix value: '' - key: readability-identifier-naming.ProtectedMemberSuffix value: '' - key: readability-identifier-naming.PublicMemberSuffix value: '' - key: readability-identifier-naming.MemberSuffix value: '' - key: readability-identifier-naming.ClassConstantSuffix value: '' - key: readability-identifier-naming.ClassMemberSuffix value: '' - key: readability-identifier-naming.GlobalConstantSuffix value: '' - key: readability-identifier-naming.GlobalConstantPointerSuffix value: '' - key: readability-identifier-naming.GlobalPointerSuffix value: '' - key: readability-identifier-naming.GlobalVariableSuffix value: '' - key: readability-identifier-naming.LocalConstantSuffix value: '' - key: readability-identifier-naming.LocalConstantPointerSuffix value: '' - key: readability-identifier-naming.LocalPointerSuffix value: '' - key: readability-identifier-naming.LocalVariableSuffix value: '' - key: readability-identifier-naming.StaticConstantSuffix value: '' - key: readability-identifier-naming.StaticVariableSuffix value: '' - key: readability-identifier-naming.ConstantSuffix value: '' - key: readability-identifier-naming.VariableSuffix value: '' - key: readability-identifier-naming.ConstantParameterSuffix value: '' - key: readability-identifier-naming.ParameterPackSuffix value: '' - key: readability-identifier-naming.ParameterSuffix value: '' - key: readability-identifier-naming.PointerParameterSuffix value: '' - key: readability-identifier-naming.ConstantPointerParameterSuffix value: '' - key: readability-identifier-naming.AbstractClassSuffix value: '' - key: readability-identifier-naming.StructSuffix value: '' - key: readability-identifier-naming.ClassSuffix value: '' - key: readability-identifier-naming.UnionSuffix value: '' - key: readability-identifier-naming.EnumSuffix value: '' - key: readability-identifier-naming.GlobalFunctionSuffix value: '' - key: readability-identifier-naming.ConstexprFunctionSuffix value: '' - key: readability-identifier-naming.FunctionSuffix value: '' - key: readability-identifier-naming.ConstexprMethodSuffix value: '' - key: readability-identifier-naming.VirtualMethodSuffix value: '' - key: readability-identifier-naming.ClassMethodSuffix value: '' - key: readability-identifier-naming.PrivateMethodSuffix value: '' - key: readability-identifier-naming.ProtectedMethodSuffix value: '' - key: readability-identifier-naming.PublicMethodSuffix value: '' - key: readability-identifier-naming.MethodSuffix value: '' - key: readability-identifier-naming.TypedefSuffix value: '' - key: readability-identifier-naming.TypeTemplateParameterSuffix value: '' - key: readability-identifier-naming.ValueTemplateParameterSuffix value: '' - key: readability-identifier-naming.TemplateTemplateParameterSuffix value: '' - key: readability-identifier-naming.TemplateParameterSuffix value: '' - key: readability-identifier-naming.TypeAliasSuffix value: '' - key: readability-identifier-naming.MacroDefinitionSuffix value: '' - key: readability-identifier-naming.ObjcIvarSuffix value: '' ... ================================================ FILE: .gcov/make/make_gcov_01_generic.gmk ================================================ # ------------------------------------------------------------------------------ # Copyright Christopher Kormanyos 2022 - 2025. # Distributed under the Boost Software License, # Version 1.0. (See accompanying file LICENSE_1_0.txt # or copy at http://www.boost.org/LICENSE_1_0.txt) # ------------------------------------------------------------------------------ PATH_MAKE = $(CURDIR) PATH_PRJ = $(PATH_MAKE)/../.. PATH_SRC = $(PATH_PRJ) PATH_BIN = $(PATH_MAKE)/bin PATH_ERR = $(PATH_MAKE)/err PATH_OBJ = $(PATH_MAKE)/obj CAT = cat GNUECHO = echo LS = ls MKDIR = mkdir GCOV = gcov LCOV = lcov GENHTML = genhtml RM = rm SED = sed include make_gcov_02_files.gmk include make_gcov_03_flags.gmk FILES_ALL = $(FILES_PRJ) FILES_O = $(addprefix $(PATH_OBJ)/, $(notdir $(addsuffix .o, $(FILES_ALL)))) FILES_GCOV = $(addprefix $(PATH_OBJ)/, $(notdir $(addsuffix .gcov, $(FILES_ALL)))) # ------------------------------------------------------------------------------ # VPATH definition: VPATH is required for make to find the source files. # ------------------------------------------------------------------------------ VPATH := $(sort $(dir $(FILES_ALL))) # ------------------------------------------------------------------------------ # Executable file: # ------------------------------------------------------------------------------ .PHONY: $(PATH_BIN)/wide_integer.exe $(PATH_BIN)/wide_integer.exe: $(FILES_O) # Link coverage-instrumented executable @$(GNUECHO) +++ link object files to $(PATH_BIN)/wide_integer.exe @$(CC) -x none $(CXXFLAGS) $(FILES_O) -o $(PATH_BIN)/wide_integer.exe @$(GNUECHO) # ------------------------------------------------------------------------------ # Main dependency: # Compile all files and link them. # Run gcov and get results. # (See also https://github.com/codecov/example-cpp11-cmake) # ------------------------------------------------------------------------------ .PHONY: gcov gcov: $(PATH_BIN)/wide_integer.exe # Obtain results @$(GNUECHO) +++ execute $(PATH_BIN)/wide_integer.exe @$(PATH_BIN)/wide_integer.exe @$(GNUECHO) @$(GNUECHO) +++ running gcov @$(GCOV) $(GCOV_FLAGS) $(addsuffix .cpp,$(FILES_PRJ)) @$(GNUECHO) @$(GNUECHO) +++ running lcov @$(LCOV) $(LCOV_BRANCH) -c --directory obj --output-file coverage_unfiltered.info @$(LCOV) $(LCOV_BRANCH) --remove coverage_unfiltered.info $(LCOV_REMOVES) --output-file coverage.info @$(GNUECHO) @$(GNUECHO) +++ running genhtml @$(GENHTML) coverage.info $(LCOV_BRANCH) --demangle-cpp --output-directory $(PATH_BIN)/report @$(GNUECHO) # ------------------------------------------------------------------------------ # Clean temporary files. # ------------------------------------------------------------------------------ .PHONY: clean clean: # creating output directories @$(GNUECHO) +++ cleaning output directories @-$(RM) -rf $(PATH_BIN)* || uname -r @-$(RM) -rf $(PATH_ERR)* || uname -r @-$(RM) -rf $(PATH_OBJ)* || uname -r @-$(RM) -f *.gcov || uname -r @-$(RM) -f coverage* || uname -r @$(GNUECHO) # ------------------------------------------------------------------------------ # Prepare the gcov build. # ------------------------------------------------------------------------------ .PHONY: prepare prepare: clean @$(GNUECHO) +++ creating output directories @-$(MKDIR) -p $(PATH_BIN) @-$(MKDIR) -p $(PATH_ERR) @-$(MKDIR) -p $(PATH_OBJ) @$(GNUECHO) @$(GNUECHO) +++ print gcov version @$(GCOV) --version @$(GNUECHO) @$(GNUECHO) +++ print include paths @$(GNUECHO) $(C_INCLUDES) @$(GNUECHO) # ------------------------------------------------------------------------------ # pattern rule for compilation of cpp-files # ------------------------------------------------------------------------------ $(PATH_OBJ)/%.o : %.cpp @-$(GNUECHO) +++ compiling: $(notdir $<) to $(notdir $(PATH_OBJ)/$(basename $(@F)).o) @-$(CC) $(CXXFLAGS) -x c++ -c $(C_INCLUDES) $(C_DEFINES) $< -o $(PATH_OBJ)/$(basename $(@F)).o 2> $(PATH_ERR)/$(basename $(@F)).err @-$(SED) -e 's|.h:\([0-9]*\),|.h(\1) :|' -e 's|:\([0-9]*\):|(\1) :|' $(PATH_ERR)/$(basename $(@F)).err ================================================ FILE: .gcov/make/make_gcov_02_files.gmk ================================================ # ------------------------------------------------------------------------------ # Copyright Christopher Kormanyos 2022 - 2026. # Distributed under the Boost Software License, # Version 1.0. (See accompanying file LICENSE_1_0.txt # or copy at http://www.boost.org/LICENSE_1_0.txt) # ------------------------------------------------------------------------------ FILES_PRJ = $(PATH_SRC)/test/test \ $(PATH_SRC)/test/test_uintwide_t_boost_backend \ $(PATH_SRC)/test/test_uintwide_t_edge_cases \ $(PATH_SRC)/test/test_uintwide_t_examples \ $(PATH_SRC)/test/test_uintwide_t_float_convert \ $(PATH_SRC)/test/test_uintwide_t_int_convert \ $(PATH_SRC)/test/test_uintwide_t_n_base \ $(PATH_SRC)/test/test_uintwide_t_n_binary_ops_base \ $(PATH_SRC)/test/test_uintwide_t_spot_values \ $(PATH_SRC)/examples/example000a_builtin_convert \ $(PATH_SRC)/examples/example000_numeric_limits \ $(PATH_SRC)/examples/example001_mul_div \ $(PATH_SRC)/examples/example001a_div_mod \ $(PATH_SRC)/examples/example002_shl_shr \ $(PATH_SRC)/examples/example003_sqrt \ $(PATH_SRC)/examples/example003a_cbrt \ $(PATH_SRC)/examples/example004_rootk_pow \ $(PATH_SRC)/examples/example005_powm \ $(PATH_SRC)/examples/example005a_pow_factors_of_p99 \ $(PATH_SRC)/examples/example006_gcd \ $(PATH_SRC)/examples/example007_random_generator \ $(PATH_SRC)/examples/example008_miller_rabin_prime \ $(PATH_SRC)/examples/example008a_miller_rabin_prime \ $(PATH_SRC)/examples/example008b_solovay_strassen_prime \ $(PATH_SRC)/examples/example009_timed_mul \ $(PATH_SRC)/examples/example009a_timed_mul_4_by_4 \ $(PATH_SRC)/examples/example009b_timed_mul_8_by_8 \ $(PATH_SRC)/examples/example010_uint48_t \ $(PATH_SRC)/examples/example011_uint24_t \ $(PATH_SRC)/examples/example012_rsa_crypto \ $(PATH_SRC)/examples/example013_ecdsa_sign_verify \ $(PATH_SRC)/examples/example014_pi_spigot_wide ================================================ FILE: .gcov/make/make_gcov_03_flags.gmk ================================================ # ------------------------------------------------------------------------------ # Copyright Christopher Kormanyos 2022 - 2026. # Distributed under the Boost Software License, # Version 1.0. (See accompanying file LICENSE_1_0.txt # or copy at http://www.boost.org/LICENSE_1_0.txt) # ------------------------------------------------------------------------------ BOOST_ROOT_FOR_GCOV = /mnt/c/boost/boost_1_90_0 CC = g++ STD = c++14 ALL_COV = 0 ifneq ($(MY_BOOST_ROOT),) BOOST_ROOT_FOR_GCOV := $(MY_BOOST_ROOT) endif ifneq ($(MY_CC),) CC := $(MY_CC) endif ifneq ($(MY_STD),) STD := $(MY_STD) endif ifneq ($(MY_STD),) STD := $(MY_STD) endif ifneq ($(MY_ALL_COV),) ALL_COV := $(MY_ALL_COV) endif CXXFLAGS = -march=native \ -mtune=native \ -O2 \ -Wall \ -Wextra \ -Wconversion \ -Wsign-conversion \ -std=$(STD) \ -pthread \ -lpthread \ -fno-inline-functions \ -fprofile-arcs \ -ftest-coverage C_DEFINES = WIDE_INTEGER_HAS_COVERAGE \ WIDE_INTEGER_HAS_LIMB_TYPE_UINT64 \ WIDE_INTEGER_HAS_MUL_8_BY_8_UNROLL C_INCLUDES = $(PATH_SRC) \ $(BOOST_ROOT_FOR_GCOV) C_DEFINES :=$(addprefix -D,$(C_DEFINES)) C_INCLUDES :=$(addprefix -I,$(C_INCLUDES)) GCOV_FLAGS = --object-directory obj \ --demangled-names # ------------------------------------------------------------------------------ # All gcov flags: The GCOV_FLAGS below are equivalent to -abcfu # ------------------------------------------------------------------------------ ifneq ($(ALL_COV),0) GCOV_FLAGS := $(GCOV_FLAGS) \ --all-blocks \ --branch-counts \ --branch-probabilities \ --function-summaries \ --unconditional-branches endif LCOV_BRANCH = ifneq ($(ALL_COV),0) LCOV_BRANCH := --rc lcov_branch_coverage=1 endif LCOV_REMOVES = '/usr/*' \ '*boost/*' ================================================ FILE: .github/toolchains/gcc.cmake ================================================ set(CMAKE_CXX_FLAGS_INIT "-Wall -Wconversion -Werror -Wextra -Wno-psabi -Wpedantic -Wshadow -Wundef") ================================================ FILE: .github/workflows/CodeQL.yml ================================================ # ------------------------------------------------------------------------------ # Copyright Christopher Kormanyos 2022 - 2026. # Distributed under the Boost Software License, # Version 1.0. (See accompanying file LICENSE_1_0.txt # or copy at http://www.boost.org/LICENSE_1_0.txt) # ------------------------------------------------------------------------------ name: CodeQL on: push: branches: - '**' pull_request: types: [opened, synchronize, reopened] jobs: analyze: name: Analyze runs-on: ubuntu-latest permissions: actions: read contents: read security-events: write strategy: fail-fast: false matrix: language: [ cpp ] steps: - name: Checkout uses: actions/checkout@v6 - name: clone-submods-bootstrap-headers-boost-develop run: | git clone -b develop --depth 1 https://github.com/boostorg/boost.git ../boost-root cd ../boost-root git submodule update --init tools git submodule update --init libs/config git submodule update --init libs/multiprecision ./bootstrap.sh ./b2 headers - name: Configure (cpp) if: ${{ matrix.language == 'cpp' }} run: echo configure_command_empty - name: Initialize CodeQL uses: github/codeql-action/init@v3 with: languages: ${{ matrix.language }} queries: +security-and-quality - name: Build cpp if: ${{ matrix.language == 'cpp' }} run: | echo 'build application on the command line' g++ -fno-exceptions -fno-rtti -finline-functions -m64 -O2 -Werror -Wall -Wextra -Wconversion -Wsign-conversion -Wshadow -Wundef -Wunused-parameter -Wuninitialized -Wunreachable-code -Winit-self -Wzero-as-null-pointer-constant -std=c++14 -DWIDE_INTEGER_HAS_LIMB_TYPE_UINT64 -I. -I../boost-root -pthread -lpthread test/test.cpp test/test_uintwide_t_boost_backend.cpp test/test_uintwide_t_edge_cases.cpp test/test_uintwide_t_examples.cpp test/test_uintwide_t_float_convert.cpp test/test_uintwide_t_int_convert.cpp test/test_uintwide_t_n_base.cpp test/test_uintwide_t_n_binary_ops_base.cpp test/test_uintwide_t_spot_values.cpp examples/example000_numeric_limits.cpp examples/example000a_builtin_convert.cpp examples/example001_mul_div.cpp examples/example001a_div_mod.cpp examples/example002_shl_shr.cpp examples/example003_sqrt.cpp examples/example003a_cbrt.cpp examples/example004_rootk_pow.cpp examples/example005_powm.cpp examples/example005a_pow_factors_of_p99.cpp examples/example006_gcd.cpp examples/example007_random_generator.cpp examples/example008_miller_rabin_prime.cpp examples/example008a_miller_rabin_prime.cpp examples/example008b_solovay_strassen_prime.cpp examples/example009_timed_mul.cpp examples/example009a_timed_mul_4_by_4.cpp examples/example009b_timed_mul_8_by_8.cpp examples/example010_uint48_t.cpp examples/example011_uint24_t.cpp examples/example012_rsa_crypto.cpp examples/example013_ecdsa_sign_verify.cpp examples/example014_pi_spigot_wide.cpp -o wide_integer.exe - name: Perform CodeQL Analysis uses: github/codeql-action/analyze@v3 with: category: "/language:${{ matrix.language }}" ================================================ FILE: .github/workflows/wide_integer.yml ================================================ # ------------------------------------------------------------------------------ # Copyright Christopher Kormanyos 2020 - 2026. # Distributed under the Boost Software License, # Version 1.0. (See accompanying file LICENSE_1_0.txt # or copy at http://www.boost.org/LICENSE_1_0.txt) # ------------------------------------------------------------------------------ name: wide_integer on: push: branches: - '**' pull_request: schedule: - cron: '5 2 * * *' # run at 2:05 AM UTC jobs: cmake-linux: runs-on: ubuntu-latest strategy: fail-fast: false matrix: compiler: [ g++, clang++ ] include: - compiler: g++ clang_tidy: "" container: johnmcfarlane/cnl_ci:gcc-11 - compiler: clang++ clang_tidy: "clang-tidy" container: johnmcfarlane/cnl_ci:clang-13-libcpp container: ${{matrix.container}} steps: - uses: actions/checkout@v6 - name: create build directory run: mkdir $GITHUB_WORKSPACE/build - name: install Boost run: | apt-get update --quiet apt-get install --no-install-recommends --quiet --yes libboost-dev - name: build working-directory: build run: | cmake \ -DCMAKE_BUILD_TYPE=Release \ -DCMAKE_CXX_STANDARD=20 \ -DCMAKE_CXX_CLANG_TIDY="${{matrix.clang_tidy}}" \ -DCMAKE_TOOLCHAIN_FILE=$GITHUB_WORKSPACE/.github/toolchains/gcc.cmake \ -GNinja \ $GITHUB_WORKSPACE cmake --build . - name: test working-directory: build run: ctest --verbose --output-on-failure cmake-windows: runs-on: windows-latest steps: - uses: actions/checkout@v6 - name: clone-boost-develop working-directory: ${{runner.workspace}} run: | git clone -b develop --depth 1 https://github.com/boostorg/boost.git ${{runner.workspace}}/boost-root - name: clone-submods working-directory: ${{runner.workspace}}/boost-root run: | git submodule update --init tools git submodule update --init libs/config git submodule update --init libs/multiprecision - uses: ilammy/msvc-dev-cmd@v1 with: toolset: 14.4 - name: bootstrap-boost working-directory: ${{runner.workspace}}/boost-root run: | ./bootstrap.bat ./b2 headers - name: create build directory run: mkdir ${{runner.workspace}}/build - name: build shell: cmd working-directory: ${{runner.workspace}}/build run: | set BOOST_ROOT=${{runner.workspace}}\boost-root cmake -DCMAKE_CXX_FLAGS="/W4 /WX /EHsc" -DCMAKE_CXX_STANDARD=20 ..\wide-integer cmake --build . --config Release - name: test working-directory: ${{runner.workspace}}/build run: ctest --verbose --output-on-failure gnumake-clang-tidy-native: runs-on: ubuntu-latest defaults: run: shell: bash strategy: fail-fast: false matrix: standard: [ c++20 ] compiler: [ g++, clang++ ] steps: - uses: actions/checkout@v6 with: fetch-depth: '0' - name: update-tools run: sudo apt install clang clang-tidy - name: clone-submods-bootstrap-headers-boost-develop run: | git clone -b develop --depth 1 https://github.com/boostorg/boost.git ../boost-root cd ../boost-root git submodule update --init tools git submodule update --init libs/config git submodule update --init libs/multiprecision ./bootstrap.sh ./b2 headers - name: gnumake-clang-tidy-native run: | grep BOOST_VERSION ../boost-root/boost/version.hpp cd .tidy/make echo "running clang-tidy" echo "make prepare -f make_tidy_01_generic.gmk MY_BOOST_ROOT=../../../boost-root MY_CC=${{ matrix.compiler }} MY_STD=${{ matrix.standard }}" echo make prepare -f make_tidy_01_generic.gmk MY_BOOST_ROOT=../../../boost-root MY_CC=${{ matrix.compiler }} MY_STD=${{ matrix.standard }} echo "make tidy -f make_tidy_01_generic.gmk --jobs=8 MY_BOOST_ROOT=../../../boost-root MY_CC=${{ matrix.compiler }} MY_STD=${{ matrix.standard }}" make tidy -f make_tidy_01_generic.gmk --jobs=8 MY_BOOST_ROOT=../../../boost-root MY_CC=${{ matrix.compiler }} MY_STD=${{ matrix.standard }} echo echo "verify empty word count of ./tmp/all.tidy_txt" wc ./tmp/all.tidy_txt | grep '0 0 0' gcc-clang-native: runs-on: ubuntu-latest defaults: run: shell: bash strategy: fail-fast: false matrix: standard: [ c++14, c++20, c++23 ] compiler: [ g++, clang++ ] steps: - uses: actions/checkout@v6 with: fetch-depth: '0' - name: clone-submods-bootstrap-headers-boost-develop run: | git clone -b develop --depth 1 https://github.com/boostorg/boost.git ../boost-root cd ../boost-root git submodule update --init tools git submodule update --init libs/config git submodule update --init libs/multiprecision ./bootstrap.sh ./b2 headers - name: gcc-clang-native run: | grep BOOST_VERSION ../boost-root/boost/version.hpp echo "compile and link to ./wide_integer via Makefile" ${{ matrix.compiler }} -v make MY_STD=${{ matrix.standard }} MY_CC=${{ matrix.compiler }} MY_BOOST_ROOT=../boost-root all echo "ls ./wide_integer" ls -la ./wide_integer ./wide_integer gcc-clang-native-limb_type_uint64_t: runs-on: ubuntu-latest defaults: run: shell: bash strategy: fail-fast: false matrix: standard: [ gnu++14, gnu++20 ] compiler: [ g++, clang++ ] steps: - uses: actions/checkout@v6 with: fetch-depth: '0' - name: clone-submods-bootstrap-headers-boost-develop run: | git clone -b develop --depth 1 https://github.com/boostorg/boost.git ../boost-root cd ../boost-root git submodule update --init tools git submodule update --init libs/config git submodule update --init libs/multiprecision ./bootstrap.sh ./b2 headers - name: gcc-clang-native-limb_type_uint64_t run: | grep BOOST_VERSION ../boost-root/boost/version.hpp echo "compile ./wide_integer.exe" ${{ matrix.compiler }} -v ${{ matrix.compiler }} -finline-functions -m64 -O3 -Werror -Wall -Wextra -Wpedantic -Wconversion -Wsign-conversion -Wshadow -Wundef -Wunused-parameter -Wuninitialized -Wunreachable-code -Winit-self -Wzero-as-null-pointer-constant -std=${{ matrix.standard }} -DWIDE_INTEGER_HAS_LIMB_TYPE_UINT64 -DWIDE_INTEGER_HAS_MUL_8_BY_8_UNROLL -I. -I../boost-root -pthread -lpthread test/test.cpp test/test_uintwide_t_boost_backend.cpp test/test_uintwide_t_edge_cases.cpp test/test_uintwide_t_examples.cpp test/test_uintwide_t_float_convert.cpp test/test_uintwide_t_int_convert.cpp test/test_uintwide_t_n_base.cpp test/test_uintwide_t_n_binary_ops_base.cpp test/test_uintwide_t_spot_values.cpp examples/example000_numeric_limits.cpp examples/example000a_builtin_convert.cpp examples/example001_mul_div.cpp examples/example001a_div_mod.cpp examples/example002_shl_shr.cpp examples/example003_sqrt.cpp examples/example003a_cbrt.cpp examples/example004_rootk_pow.cpp examples/example005_powm.cpp examples/example005a_pow_factors_of_p99.cpp examples/example006_gcd.cpp examples/example007_random_generator.cpp examples/example008_miller_rabin_prime.cpp examples/example008a_miller_rabin_prime.cpp examples/example008b_solovay_strassen_prime.cpp examples/example009_timed_mul.cpp examples/example009a_timed_mul_4_by_4.cpp examples/example009b_timed_mul_8_by_8.cpp examples/example010_uint48_t.cpp examples/example011_uint24_t.cpp examples/example012_rsa_crypto.cpp examples/example013_ecdsa_sign_verify.cpp examples/example014_pi_spigot_wide.cpp -o wide_integer.exe echo "ls ./wide_integer.exe" ls -la ./wide_integer.exe ./wide_integer.exe gcc-clang-wide_integer_namespace: runs-on: ubuntu-latest defaults: run: shell: bash strategy: fail-fast: false matrix: standard: [ c++14, c++20 ] compiler: [ g++, clang++ ] steps: - uses: actions/checkout@v6 with: fetch-depth: '0' - name: clone-submods-bootstrap-headers-boost-develop run: | git clone -b develop --depth 1 https://github.com/boostorg/boost.git ../boost-root cd ../boost-root git submodule update --init tools git submodule update --init libs/config git submodule update --init libs/multiprecision ./bootstrap.sh ./b2 headers - name: gcc-clang-wide_integer_namespace run: | grep BOOST_VERSION ../boost-root/boost/version.hpp echo "compile ./wide_integer.exe" ${{ matrix.compiler }} -v ${{ matrix.compiler }} -finline-functions -m64 -O3 -Werror -Wall -Wextra -Wpedantic -Wconversion -Wsign-conversion -Wshadow -Wundef -Wunused-parameter -Wuninitialized -Wunreachable-code -Winit-self -Wzero-as-null-pointer-constant -std=${{ matrix.standard }} -DWIDE_INTEGER_NAMESPACE=ckormanyos -DWIDE_INTEGER_HAS_LIMB_TYPE_UINT64 -I. -I../boost-root -pthread -lpthread test/test.cpp test/test_uintwide_t_boost_backend.cpp test/test_uintwide_t_edge_cases.cpp test/test_uintwide_t_examples.cpp test/test_uintwide_t_float_convert.cpp test/test_uintwide_t_int_convert.cpp test/test_uintwide_t_n_base.cpp test/test_uintwide_t_n_binary_ops_base.cpp test/test_uintwide_t_spot_values.cpp examples/example000_numeric_limits.cpp examples/example000a_builtin_convert.cpp examples/example001_mul_div.cpp examples/example001a_div_mod.cpp examples/example002_shl_shr.cpp examples/example003_sqrt.cpp examples/example003a_cbrt.cpp examples/example004_rootk_pow.cpp examples/example005_powm.cpp examples/example005a_pow_factors_of_p99.cpp examples/example006_gcd.cpp examples/example007_random_generator.cpp examples/example008_miller_rabin_prime.cpp examples/example008a_miller_rabin_prime.cpp examples/example008b_solovay_strassen_prime.cpp examples/example009_timed_mul.cpp examples/example009a_timed_mul_4_by_4.cpp examples/example009b_timed_mul_8_by_8.cpp examples/example010_uint48_t.cpp examples/example011_uint24_t.cpp examples/example012_rsa_crypto.cpp examples/example013_ecdsa_sign_verify.cpp examples/example014_pi_spigot_wide.cpp -o wide_integer.exe echo "ls ./wide_integer.exe" ls -la ./wide_integer.exe ./wide_integer.exe gcc-clang-native-asan: runs-on: ubuntu-latest defaults: run: shell: bash strategy: fail-fast: false matrix: standard: [ c++14, c++20 ] compiler: [ g++, clang++ ] steps: - uses: actions/checkout@v6 with: fetch-depth: '0' - name: clone-submods-bootstrap-headers-boost-develop run: | git clone -b develop --depth 1 https://github.com/boostorg/boost.git ../boost-root cd ../boost-root git submodule update --init tools git submodule update --init libs/config git submodule update --init libs/multiprecision ./bootstrap.sh ./b2 headers - name: gcc-clang-native-asan run: | grep BOOST_VERSION ../boost-root/boost/version.hpp echo "compile ./wide_integer.exe" ${{ matrix.compiler }} -v ${{ matrix.compiler }} -fno-exceptions -fno-rtti -fsanitize=address -fsanitize=leak -m64 -O1 -Werror -Wall -Wextra -Wpedantic -Wconversion -Wsign-conversion -Wshadow -Wundef -Wunused-parameter -Wuninitialized -Wunreachable-code -Winit-self -Wzero-as-null-pointer-constant -std=${{ matrix.standard }} -DWIDE_INTEGER_HAS_LIMB_TYPE_UINT64 -I. -I../boost-root -pthread -lpthread test/test.cpp test/test_uintwide_t_boost_backend.cpp test/test_uintwide_t_edge_cases.cpp test/test_uintwide_t_examples.cpp test/test_uintwide_t_float_convert.cpp test/test_uintwide_t_int_convert.cpp test/test_uintwide_t_n_base.cpp test/test_uintwide_t_n_binary_ops_base.cpp test/test_uintwide_t_spot_values.cpp examples/example000_numeric_limits.cpp examples/example000a_builtin_convert.cpp examples/example001_mul_div.cpp examples/example001a_div_mod.cpp examples/example002_shl_shr.cpp examples/example003_sqrt.cpp examples/example003a_cbrt.cpp examples/example004_rootk_pow.cpp examples/example005_powm.cpp examples/example005a_pow_factors_of_p99.cpp examples/example006_gcd.cpp examples/example007_random_generator.cpp examples/example008_miller_rabin_prime.cpp examples/example008a_miller_rabin_prime.cpp examples/example008b_solovay_strassen_prime.cpp examples/example009_timed_mul.cpp examples/example009a_timed_mul_4_by_4.cpp examples/example009b_timed_mul_8_by_8.cpp examples/example010_uint48_t.cpp examples/example011_uint24_t.cpp examples/example012_rsa_crypto.cpp examples/example013_ecdsa_sign_verify.cpp examples/example014_pi_spigot_wide.cpp -o wide_integer.exe echo "ls ./wide_integer.exe" ls -la ./wide_integer.exe setarch `uname -m` -R ./wide_integer.exe gcc-clang-native-asan-clz: runs-on: ubuntu-latest defaults: run: shell: bash strategy: fail-fast: false matrix: compiler: [ g++, clang++ ] steps: - uses: actions/checkout@v6 with: fetch-depth: '0' - name: clone-submods-bootstrap-headers-boost-develop run: | git clone -b develop --depth 1 https://github.com/boostorg/boost.git ../boost-root cd ../boost-root git submodule update --init tools git submodule update --init libs/config git submodule update --init libs/multiprecision ./bootstrap.sh ./b2 headers - name: gcc-clang-native-asan-clz run: | grep BOOST_VERSION ../boost-root/boost/version.hpp echo "compile ./wide_integer.exe" ${{ matrix.compiler }} -v ${{ matrix.compiler }} -fno-exceptions -fno-rtti -fsanitize=address -fsanitize=leak -m64 -O1 -Werror -Wall -Wextra -Wpedantic -Wconversion -Wsign-conversion -Wshadow -Wundef -Wunused-parameter -Wuninitialized -Wunreachable-code -Winit-self -Wzero-as-null-pointer-constant -std=c++14 -DWIDE_INTEGER_HAS_CLZ_LIMB_OPTIMIZATIONS -DWIDE_INTEGER_HAS_LIMB_TYPE_UINT64 -I. -I../boost-root -pthread -lpthread test/test.cpp test/test_uintwide_t_boost_backend.cpp test/test_uintwide_t_edge_cases.cpp test/test_uintwide_t_examples.cpp test/test_uintwide_t_float_convert.cpp test/test_uintwide_t_int_convert.cpp test/test_uintwide_t_n_base.cpp test/test_uintwide_t_n_binary_ops_base.cpp test/test_uintwide_t_spot_values.cpp examples/example000_numeric_limits.cpp examples/example000a_builtin_convert.cpp examples/example001_mul_div.cpp examples/example001a_div_mod.cpp examples/example002_shl_shr.cpp examples/example003_sqrt.cpp examples/example003a_cbrt.cpp examples/example004_rootk_pow.cpp examples/example005_powm.cpp examples/example005a_pow_factors_of_p99.cpp examples/example006_gcd.cpp examples/example007_random_generator.cpp examples/example008_miller_rabin_prime.cpp examples/example008a_miller_rabin_prime.cpp examples/example008b_solovay_strassen_prime.cpp examples/example009_timed_mul.cpp examples/example009a_timed_mul_4_by_4.cpp examples/example009b_timed_mul_8_by_8.cpp examples/example010_uint48_t.cpp examples/example011_uint24_t.cpp examples/example012_rsa_crypto.cpp examples/example013_ecdsa_sign_verify.cpp examples/example014_pi_spigot_wide.cpp -o wide_integer.exe echo "ls ./wide_integer.exe" ls -la ./wide_integer.exe setarch `uname -m` -R ./wide_integer.exe gcc-clang-native-ubsan: runs-on: ubuntu-latest defaults: run: shell: bash strategy: fail-fast: false matrix: standard: [ c++14, c++20 ] compiler: [ g++, clang++ ] steps: - uses: actions/checkout@v6 with: fetch-depth: '0' - name: clone-submods-bootstrap-headers-boost-develop run: | git clone -b develop --depth 1 https://github.com/boostorg/boost.git ../boost-root cd ../boost-root git submodule update --init tools git submodule update --init libs/config git submodule update --init libs/multiprecision ./bootstrap.sh ./b2 headers - name: gcc-clang-native-ubsan run: | grep BOOST_VERSION ../boost-root/boost/version.hpp echo "compile ./wide_integer.exe" ${{ matrix.compiler }} -v ${{ matrix.compiler }} -finline-functions -fsanitize=shift -fsanitize=shift-exponent -fsanitize=shift-base -fsanitize=integer-divide-by-zero -fsanitize=null -fsanitize=signed-integer-overflow -fsanitize=bounds -fsanitize=alignment -fsanitize=float-divide-by-zero -fsanitize=float-cast-overflow -fsanitize=enum -m64 -O3 -Werror -Wall -Wextra -Wpedantic -Wconversion -Wsign-conversion -Wshadow -Wundef -Wunused-parameter -Wuninitialized -Wunreachable-code -Winit-self -Wzero-as-null-pointer-constant -std=${{ matrix.standard }} -DWIDE_INTEGER_HAS_LIMB_TYPE_UINT64 -I. -I../boost-root -pthread -lpthread test/test.cpp test/test_uintwide_t_boost_backend.cpp test/test_uintwide_t_edge_cases.cpp test/test_uintwide_t_examples.cpp test/test_uintwide_t_float_convert.cpp test/test_uintwide_t_int_convert.cpp test/test_uintwide_t_n_base.cpp test/test_uintwide_t_n_binary_ops_base.cpp test/test_uintwide_t_spot_values.cpp examples/example000_numeric_limits.cpp examples/example000a_builtin_convert.cpp examples/example001_mul_div.cpp examples/example001a_div_mod.cpp examples/example002_shl_shr.cpp examples/example003_sqrt.cpp examples/example003a_cbrt.cpp examples/example004_rootk_pow.cpp examples/example005_powm.cpp examples/example005a_pow_factors_of_p99.cpp examples/example006_gcd.cpp examples/example007_random_generator.cpp examples/example008_miller_rabin_prime.cpp examples/example008a_miller_rabin_prime.cpp examples/example008b_solovay_strassen_prime.cpp examples/example009_timed_mul.cpp examples/example009a_timed_mul_4_by_4.cpp examples/example009b_timed_mul_8_by_8.cpp examples/example010_uint48_t.cpp examples/example011_uint24_t.cpp examples/example012_rsa_crypto.cpp examples/example013_ecdsa_sign_verify.cpp examples/example014_pi_spigot_wide.cpp -o wide_integer.exe echo "ls ./wide_integer.exe" ls -la ./wide_integer.exe ./wide_integer.exe gcc-clang-native-ubsan-limb_type_uint64_t: runs-on: ubuntu-latest defaults: run: shell: bash strategy: fail-fast: false matrix: standard: [ gnu++14, gnu++20 ] compiler: [ g++, clang++ ] steps: - uses: actions/checkout@v6 with: fetch-depth: '0' - name: clone-submods-bootstrap-headers-boost-develop run: | git clone -b develop --depth 1 https://github.com/boostorg/boost.git ../boost-root cd ../boost-root git submodule update --init tools git submodule update --init libs/config git submodule update --init libs/multiprecision ./bootstrap.sh ./b2 headers - name: gcc-clang-native-ubsan-limb_type_uint64_t run: | grep BOOST_VERSION ../boost-root/boost/version.hpp echo "compile ./wide_integer.exe" ${{ matrix.compiler }} -v ${{ matrix.compiler }} -finline-functions -fsanitize=shift -fsanitize=shift-exponent -fsanitize=shift-base -fsanitize=integer-divide-by-zero -fsanitize=null -fsanitize=signed-integer-overflow -fsanitize=bounds -fsanitize=alignment -fsanitize=float-divide-by-zero -fsanitize=float-cast-overflow -fsanitize=enum -m64 -O3 -Werror -Wall -Wextra -Wpedantic -Wconversion -Wsign-conversion -Wshadow -Wundef -Wunused-parameter -Wuninitialized -Wunreachable-code -Winit-self -Wzero-as-null-pointer-constant -std=${{ matrix.standard }} -DWIDE_INTEGER_HAS_LIMB_TYPE_UINT64 -DWIDE_INTEGER_HAS_LIMB_TYPE_UINT64 -I. -I../boost-root -pthread -lpthread test/test.cpp test/test_uintwide_t_boost_backend.cpp test/test_uintwide_t_edge_cases.cpp test/test_uintwide_t_examples.cpp test/test_uintwide_t_float_convert.cpp test/test_uintwide_t_int_convert.cpp test/test_uintwide_t_n_base.cpp test/test_uintwide_t_n_binary_ops_base.cpp test/test_uintwide_t_spot_values.cpp examples/example000_numeric_limits.cpp examples/example000a_builtin_convert.cpp examples/example001_mul_div.cpp examples/example001a_div_mod.cpp examples/example002_shl_shr.cpp examples/example003_sqrt.cpp examples/example003a_cbrt.cpp examples/example004_rootk_pow.cpp examples/example005_powm.cpp examples/example005a_pow_factors_of_p99.cpp examples/example006_gcd.cpp examples/example007_random_generator.cpp examples/example008_miller_rabin_prime.cpp examples/example008a_miller_rabin_prime.cpp examples/example008b_solovay_strassen_prime.cpp examples/example009_timed_mul.cpp examples/example009a_timed_mul_4_by_4.cpp examples/example009b_timed_mul_8_by_8.cpp examples/example010_uint48_t.cpp examples/example011_uint24_t.cpp examples/example012_rsa_crypto.cpp examples/example013_ecdsa_sign_verify.cpp examples/example014_pi_spigot_wide.cpp -o wide_integer.exe echo "ls ./wide_integer.exe" ls -la ./wide_integer.exe ./wide_integer.exe gcc-clang-native-ubsan-clz: runs-on: ubuntu-latest defaults: run: shell: bash strategy: fail-fast: false matrix: compiler: [ g++, clang++ ] steps: - uses: actions/checkout@v6 with: fetch-depth: '0' - name: clone-submods-bootstrap-headers-boost-develop run: | git clone -b develop --depth 1 https://github.com/boostorg/boost.git ../boost-root cd ../boost-root git submodule update --init tools git submodule update --init libs/config git submodule update --init libs/multiprecision ./bootstrap.sh ./b2 headers - name: gcc-clang-native-ubsan-clz run: | grep BOOST_VERSION ../boost-root/boost/version.hpp echo "compile ./wide_integer.exe" ${{ matrix.compiler }} -v ${{ matrix.compiler }} -finline-functions -fsanitize=shift -fsanitize=shift-exponent -fsanitize=shift-base -fsanitize=integer-divide-by-zero -fsanitize=null -fsanitize=signed-integer-overflow -fsanitize=bounds -fsanitize=alignment -fsanitize=float-divide-by-zero -fsanitize=float-cast-overflow -fsanitize=enum -m64 -O3 -Werror -Wall -Wextra -Wpedantic -Wconversion -Wsign-conversion -Wshadow -Wundef -Wunused-parameter -Wuninitialized -Wunreachable-code -Winit-self -Wzero-as-null-pointer-constant -std=c++14 -DWIDE_INTEGER_HAS_CLZ_LIMB_OPTIMIZATIONS -DWIDE_INTEGER_HAS_LIMB_TYPE_UINT64 -I. -I../boost-root -pthread -lpthread test/test.cpp test/test_uintwide_t_boost_backend.cpp test/test_uintwide_t_edge_cases.cpp test/test_uintwide_t_examples.cpp test/test_uintwide_t_float_convert.cpp test/test_uintwide_t_int_convert.cpp test/test_uintwide_t_n_base.cpp test/test_uintwide_t_n_binary_ops_base.cpp test/test_uintwide_t_spot_values.cpp examples/example000_numeric_limits.cpp examples/example000a_builtin_convert.cpp examples/example001_mul_div.cpp examples/example001a_div_mod.cpp examples/example002_shl_shr.cpp examples/example003_sqrt.cpp examples/example003a_cbrt.cpp examples/example004_rootk_pow.cpp examples/example005_powm.cpp examples/example005a_pow_factors_of_p99.cpp examples/example006_gcd.cpp examples/example007_random_generator.cpp examples/example008_miller_rabin_prime.cpp examples/example008a_miller_rabin_prime.cpp examples/example008b_solovay_strassen_prime.cpp examples/example009_timed_mul.cpp examples/example009a_timed_mul_4_by_4.cpp examples/example009b_timed_mul_8_by_8.cpp examples/example010_uint48_t.cpp examples/example011_uint24_t.cpp examples/example012_rsa_crypto.cpp examples/example013_ecdsa_sign_verify.cpp examples/example014_pi_spigot_wide.cpp -o wide_integer.exe echo "ls ./wide_integer.exe" ls -la ./wide_integer.exe ./wide_integer.exe gcc-clang-native-tsan: runs-on: ubuntu-latest defaults: run: shell: bash strategy: fail-fast: false matrix: standard: [ c++14, c++20 ] compiler: [ g++, clang++ ] steps: - uses: actions/checkout@v6 with: fetch-depth: '0' - name: clone-submods-bootstrap-headers-boost-develop run: | git clone -b develop --depth 1 https://github.com/boostorg/boost.git ../boost-root cd ../boost-root git submodule update --init tools git submodule update --init libs/config git submodule update --init libs/multiprecision ./bootstrap.sh ./b2 headers - name: gcc-clang-native-tsan run: | grep BOOST_VERSION ../boost-root/boost/version.hpp echo "compile ./wide_integer.exe" ${{ matrix.compiler }} -v ${{ matrix.compiler }} -fno-exceptions -fno-rtti -fsanitize=thread -m64 -O1 -Werror -Wall -Wextra -Wpedantic -Wconversion -Wsign-conversion -Wshadow -Wundef -Wunused-parameter -Wuninitialized -Wunreachable-code -Winit-self -Wzero-as-null-pointer-constant -std=${{ matrix.standard }} -DWIDE_INTEGER_HAS_LIMB_TYPE_UINT64 -I. -I../boost-root -pthread -lpthread test/test.cpp test/test_uintwide_t_boost_backend.cpp test/test_uintwide_t_edge_cases.cpp test/test_uintwide_t_examples.cpp test/test_uintwide_t_float_convert.cpp test/test_uintwide_t_int_convert.cpp test/test_uintwide_t_n_base.cpp test/test_uintwide_t_n_binary_ops_base.cpp test/test_uintwide_t_spot_values.cpp examples/example000_numeric_limits.cpp examples/example000a_builtin_convert.cpp examples/example001_mul_div.cpp examples/example001a_div_mod.cpp examples/example002_shl_shr.cpp examples/example003_sqrt.cpp examples/example003a_cbrt.cpp examples/example004_rootk_pow.cpp examples/example005_powm.cpp examples/example005a_pow_factors_of_p99.cpp examples/example006_gcd.cpp examples/example007_random_generator.cpp examples/example008_miller_rabin_prime.cpp examples/example008a_miller_rabin_prime.cpp examples/example008b_solovay_strassen_prime.cpp examples/example009_timed_mul.cpp examples/example009a_timed_mul_4_by_4.cpp examples/example009b_timed_mul_8_by_8.cpp examples/example010_uint48_t.cpp examples/example011_uint24_t.cpp examples/example012_rsa_crypto.cpp examples/example013_ecdsa_sign_verify.cpp examples/example014_pi_spigot_wide.cpp -o wide_integer.exe echo "ls ./wide_integer.exe" ls -la ./wide_integer.exe setarch `uname -m` -R ./wide_integer.exe apple-gcc-clang-native: runs-on: macos-latest defaults: run: shell: bash strategy: fail-fast: false matrix: standard: [ c++14, c++20 ] compiler: [ g++, clang++ ] steps: - uses: actions/checkout@v6 with: fetch-depth: '0' - name: clone-submods-bootstrap-headers-boost-develop run: | git clone -b develop --depth 1 https://github.com/boostorg/boost.git ../boost-root cd ../boost-root git submodule update --init tools git submodule update --init libs/config git submodule update --init libs/multiprecision ./bootstrap.sh ./b2 headers - name: apple-gcc-clang-native run: | grep BOOST_VERSION ../boost-root/boost/version.hpp echo "compile ./wide_integer.exe" ${{ matrix.compiler }} -v ${{ matrix.compiler }} -finline-functions -m64 -O3 -Werror -Wall -Wextra -Wpedantic -Wconversion -Wsign-conversion -Wshadow -Wundef -Wunused-parameter -Wuninitialized -Wunreachable-code -Winit-self -Wzero-as-null-pointer-constant -std=${{ matrix.standard }} -DWIDE_INTEGER_HAS_LIMB_TYPE_UINT64 -I. -I../boost-root -pthread -lpthread test/test.cpp test/test_uintwide_t_boost_backend.cpp test/test_uintwide_t_edge_cases.cpp test/test_uintwide_t_examples.cpp test/test_uintwide_t_float_convert.cpp test/test_uintwide_t_int_convert.cpp test/test_uintwide_t_n_base.cpp test/test_uintwide_t_n_binary_ops_base.cpp test/test_uintwide_t_spot_values.cpp examples/example000_numeric_limits.cpp examples/example000a_builtin_convert.cpp examples/example001_mul_div.cpp examples/example001a_div_mod.cpp examples/example002_shl_shr.cpp examples/example003_sqrt.cpp examples/example003a_cbrt.cpp examples/example004_rootk_pow.cpp examples/example005_powm.cpp examples/example005a_pow_factors_of_p99.cpp examples/example006_gcd.cpp examples/example007_random_generator.cpp examples/example008_miller_rabin_prime.cpp examples/example008a_miller_rabin_prime.cpp examples/example008b_solovay_strassen_prime.cpp examples/example009_timed_mul.cpp examples/example009a_timed_mul_4_by_4.cpp examples/example009b_timed_mul_8_by_8.cpp examples/example010_uint48_t.cpp examples/example011_uint24_t.cpp examples/example012_rsa_crypto.cpp examples/example013_ecdsa_sign_verify.cpp examples/example014_pi_spigot_wide.cpp -o wide_integer.exe echo "ls ./wide_integer.exe" ls -la ./wide_integer.exe ./wide_integer.exe msvc-release-x64: runs-on: windows-latest steps: - uses: actions/checkout@v6 with: fetch-depth: '0' - name: clone-submods-bootstrap-headers-boost-develop run: | git clone -b develop --depth 1 https://github.com/boostorg/boost.git ../boost-root cd ../boost-root git submodule update --init tools git submodule update --init libs/config git submodule update --init libs/multiprecision - uses: actions/checkout@v6 - uses: ilammy/msvc-dev-cmd@v1 with: toolset: 14.2 - name: bootstrap-boost working-directory: ${{ runner.workspace }}/boost-root run: | ./bootstrap.bat ./b2 headers - name: msvc-release-x64 shell: cmd working-directory: ./ run: | set INCLUDE=%cd%;%cd%\..\boost-root;%INCLUDE% MSBuild -m wide_integer.sln -p:useenv=true -p:Configuration=Release -p:Platform=x64 /t:Rebuild dir %cd%\x64\Release\wide_integer.exe %cd%\x64\Release\wide_integer.exe msvc-release-x64-vs2022: runs-on: windows-latest steps: - uses: actions/checkout@v6 - name: clone-boost-develop working-directory: ${{ runner.workspace }} run: | git clone -b develop --depth 1 https://github.com/boostorg/boost.git ${{ runner.workspace }}/boost-root - name: clone-boost-submods working-directory: ${{ runner.workspace }}/boost-root run: | git submodule update --init tools git submodule update --init libs/config git submodule update --init libs/multiprecision - uses: ilammy/msvc-dev-cmd@v1 with: toolset: 14.4 - name: bootstrap-boost working-directory: ${{ runner.workspace }}/boost-root run: | ./bootstrap.bat ./b2 headers - name: msvc-release-x64-vs2022 shell: cmd working-directory: ./ run: | set INCLUDE=%cd% set INCLUDE=${{ runner.workspace }}\boost-root;%INCLUDE% MSBuild -m wide_integer_vs2022.sln -p:useenv=true -p:Configuration=Release -p:Platform=x64 /t:Rebuild dir %cd%\x64\Release\wide_integer_vs2022.exe %cd%\x64\Release\wide_integer_vs2022.exe msys2-winhost-x64: runs-on: windows-latest defaults: run: shell: msys2 {0} strategy: fail-fast: false matrix: compiler: [ g++ ] standard: [ c++14, c++20 ] steps: - uses: actions/checkout@v6 with: fetch-depth: '0' - uses: msys2/setup-msys2@v2 with: msystem: UCRT64 update: true install: git mingw-w64-ucrt-x86_64-gcc - name: clone-submods-bootstrap-headers-boost-develop run: | git clone -b develop --depth 1 https://github.com/boostorg/boost.git ../boost-root cd ../boost-root git submodule update --init tools git submodule update --init libs/config git submodule update --init libs/multiprecision ./bootstrap.sh ./b2 headers - name: msys2-winhost-x64 working-directory: ./ run: | echo compile ./wide_integer.exe ${{ matrix.compiler }} -v ${{ matrix.compiler }} -finline-functions -m64 -O3 -Wall -Wextra -Wpedantic -Wconversion -Wsign-conversion -Wshadow -Wundef -Wunused-parameter -Wuninitialized -Wunreachable-code -Winit-self -Wzero-as-null-pointer-constant -std=${{ matrix.standard }} -DWIDE_INTEGER_HAS_LIMB_TYPE_UINT64 -I. -I../boost-root -pthread -lpthread test/test.cpp test/test_uintwide_t_boost_backend.cpp test/test_uintwide_t_edge_cases.cpp test/test_uintwide_t_examples.cpp test/test_uintwide_t_float_convert.cpp test/test_uintwide_t_int_convert.cpp test/test_uintwide_t_n_base.cpp test/test_uintwide_t_n_binary_ops_base.cpp test/test_uintwide_t_spot_values.cpp examples/example000_numeric_limits.cpp examples/example000a_builtin_convert.cpp examples/example001_mul_div.cpp examples/example001a_div_mod.cpp examples/example002_shl_shr.cpp examples/example003_sqrt.cpp examples/example003a_cbrt.cpp examples/example004_rootk_pow.cpp examples/example005_powm.cpp examples/example005a_pow_factors_of_p99.cpp examples/example006_gcd.cpp examples/example007_random_generator.cpp examples/example008_miller_rabin_prime.cpp examples/example008a_miller_rabin_prime.cpp examples/example008b_solovay_strassen_prime.cpp examples/example009_timed_mul.cpp examples/example009a_timed_mul_4_by_4.cpp examples/example009b_timed_mul_8_by_8.cpp examples/example010_uint48_t.cpp examples/example011_uint24_t.cpp examples/example012_rsa_crypto.cpp examples/example013_ecdsa_sign_verify.cpp examples/example014_pi_spigot_wide.cpp -o wide_integer.exe ls -la ./wide_integer.exe ./wide_integer.exe cygwin-winhost-x64: runs-on: windows-latest strategy: fail-fast: false matrix: compiler: [ g++ ] standard: [ c++17, c++20 ] steps: - uses: actions/checkout@v6 with: fetch-depth: '0' - name: clone-submods-boost-develop run: | git clone -b develop --depth 1 https://github.com/boostorg/boost.git ../boost-root cd ../boost-root git submodule update --init tools git submodule update --init libs/config git submodule update --init libs/multiprecision - uses: cygwin/cygwin-install-action@master with: check-sig: false site: https://ftp.fau.de/cygwin/ packages: gcc-core gcc-g++ - name: boost-bootstrap run: bash -l -c 'cd $(cygpath -u "$GITHUB_WORKSPACE")/../boost-root && ./bootstrap.sh' - name: boost-generate-headers run: bash -l -c 'cd $(cygpath -u "$GITHUB_WORKSPACE")/../boost-root && ./b2 headers' - name: query-gcc-version run: bash -l -c 'cd $(cygpath -u "$GITHUB_WORKSPACE") && echo print-compiler-version && ${{ matrix.compiler }} -v' - name: wide-integer-compile run: bash -l -c 'cd $(cygpath -u "$GITHUB_WORKSPACE") && ${{ matrix.compiler }} -finline-functions -m64 -O2 -Werror -Wall -Wextra -Wpedantic -Wconversion -Wsign-conversion -Wshadow -Wundef -Wunused-parameter -Wuninitialized -Wunreachable-code -Winit-self -Wzero-as-null-pointer-constant -std=${{ matrix.standard }} -DWIDE_INTEGER_HAS_LIMB_TYPE_UINT64 -I. -I../boost-root -pthread -lpthread test/test.cpp test/test_uintwide_t_boost_backend.cpp test/test_uintwide_t_edge_cases.cpp test/test_uintwide_t_examples.cpp test/test_uintwide_t_float_convert.cpp test/test_uintwide_t_int_convert.cpp test/test_uintwide_t_n_base.cpp test/test_uintwide_t_n_binary_ops_base.cpp test/test_uintwide_t_spot_values.cpp examples/example000_numeric_limits.cpp examples/example000a_builtin_convert.cpp examples/example001_mul_div.cpp examples/example001a_div_mod.cpp examples/example002_shl_shr.cpp examples/example003_sqrt.cpp examples/example003a_cbrt.cpp examples/example004_rootk_pow.cpp examples/example005_powm.cpp examples/example005a_pow_factors_of_p99.cpp examples/example006_gcd.cpp examples/example007_random_generator.cpp examples/example008_miller_rabin_prime.cpp examples/example008a_miller_rabin_prime.cpp examples/example008b_solovay_strassen_prime.cpp examples/example009_timed_mul.cpp examples/example009a_timed_mul_4_by_4.cpp examples/example009b_timed_mul_8_by_8.cpp examples/example010_uint48_t.cpp examples/example011_uint24_t.cpp examples/example012_rsa_crypto.cpp examples/example013_ecdsa_sign_verify.cpp examples/example014_pi_spigot_wide.cpp -o wide_integer.exe' - name: wide-integer-run run: bash -l -c 'cd $(cygpath -u "$GITHUB_WORKSPACE") && ./wide_integer.exe' gcc-arm-none-eabi: runs-on: ubuntu-latest defaults: run: shell: bash strategy: fail-fast: false matrix: example: [ example001_mul_div, example003_sqrt ] standard: [ c++14 ] steps: - uses: actions/checkout@v6 with: fetch-depth: '0' - name: update-tools run: | sudo apt update wget http://security.ubuntu.com/ubuntu/pool/universe/n/ncurses/libtinfo5_6.3-2ubuntu0.1_amd64.deb sudo apt install ./libtinfo5_6.3-2ubuntu0.1_amd64.deb wget http://security.ubuntu.com/ubuntu/pool/universe/n/ncurses/libncursesw5_6.3-2ubuntu0.1_amd64.deb sudo apt install ./libncursesw5_6.3-2ubuntu0.1_amd64.deb mkdir -p emu_env && cd emu_env wget --no-check-certificate https://developer.arm.com/-/media/Files/downloads/gnu/13.3.rel1/binrel/arm-gnu-toolchain-13.3.rel1-x86_64-arm-none-eabi.tar.xz tar -xf arm-gnu-toolchain-13.3.rel1-x86_64-arm-none-eabi.tar.xz wget --no-check-certificate https://github.com/xpack-dev-tools/qemu-arm-xpack/releases/download/v8.2.6-1/xpack-qemu-arm-8.2.6-1-linux-x64.tar.gz tar -xzf xpack-qemu-arm-8.2.6-1-linux-x64.tar.gz working-directory: ./ - id: upcase_my_example uses: ASzc/change-string-case-action@v6 with: string: ${{ matrix.example }} - name: build-example-stm32f429 run: | PATH="${{ runner.workspace }}/wide-integer/emu_env/arm-gnu-toolchain-13.3.rel1-x86_64-arm-none-eabi/bin:$PATH" echo 'Query arm-none-eabi-g++ version' echo arm-none-eabi-g++ -v echo mkdir -p bin arm-none-eabi-g++ -std=${{ matrix.standard }} -Werror -Wall -Wextra -Wpedantic -Wpedantic -Wconversion -Wsign-conversion -O1 -g -gdwarf-2 -ffunction-sections -fdata-sections -x c++ -fno-rtti -fno-use-cxa-atexit -fno-exceptions -fno-nonansi-builtins -fno-threadsafe-statics -fno-enforce-eh-specs -ftemplate-depth=32 -mcpu=cortex-m4 -mtune=cortex-m4 -mthumb -mfloat-abi=soft -mno-unaligned-access -mno-long-calls -I. -DWIDE_INTEGER_DISABLE_IOSTREAM -DWIDE_INTEGER_DISABLE_TO_STRING -DWIDE_INTEGER_DISABLE_TRIVIAL_COPY_AND_STD_LAYOUT_CHECKS -DWIDE_INTEGER_NAMESPACE=ckormanyos -DWIDE_INTEGER_STANDALONE_${{ steps.upcase_my_example.outputs.uppercase }} examples/${{ matrix.example }}.cpp ./target/micros/stm32f429/make/single/crt.cpp -nostartfiles -Wl,--gc-sections -Wl,-Map,./bin/${{ matrix.example }}.map -T ./target/micros/stm32f429/make/stm32f429.ld --specs=nano.specs --specs=nosys.specs -o ./bin/${{ matrix.example }}.elf arm-none-eabi-objcopy ./bin/${{ matrix.example }}.elf -O ihex ./bin/${{ matrix.example }}.hex ls -la ./bin/${{ matrix.example }}.elf ./bin/${{ matrix.example }}.hex ./bin/${{ matrix.example }}.map working-directory: ./ - name: emulate-target stm32f429 run: | PATH="${{ runner.workspace }}/wide-integer/emu_env/xpack-qemu-arm-8.2.6-1/bin:$PATH" qemu-system-gnuarmeclipse --verbose --mcu STM32F429ZI --nographic --gdb tcp::9999 -d unimp,guest_errors & sleep 2 working-directory: ./ - name: run-test-on-target run: | sleep 2 PATH="${{ runner.workspace }}/wide-integer/emu_env/arm-gnu-toolchain-13.3.rel1-x86_64-arm-none-eabi/bin:$PATH" echo 'Run test on target' echo arm-none-eabi-gdb ./bin/${{ matrix.example }}.elf -x ./target/build/test_examples_emulator.gdb > ./${{ matrix.example }}.txt cat ./${{ matrix.example }}.txt echo echo 'We will now grep for the right answer...' grep 'value 0xF00DCAFE' ./${{ matrix.example }}.txt working-directory: ./ gcc-avr: runs-on: ubuntu-latest defaults: run: shell: bash strategy: fail-fast: false matrix: example: [ example001_mul_div, example003_sqrt ] standard: [ c++14 ] steps: - uses: actions/checkout@v6 with: fetch-depth: '0' - name: update-tools run: sudo apt install gcc-avr avr-libc - name: clone-real-time-cpp run: | git clone -b master --depth 1 https://github.com/ckormanyos/real-time-cpp.git ../real-time-cpp-root working-directory: ./ - id: upcase_my_example uses: ASzc/change-string-case-action@v6 with: string: ${{ matrix.example }} - name: gcc-avr run: | mkdir bin echo ${{ steps.upcase_my_example.outputs.uppercase }} echo 'compile examples/${{ matrix.example }}.cpp with:' echo 'avr-g++ -x c++ -std=${{ matrix.standard }} -Os -Werror -Wall -Wextra -Wpedantic -Wpedantic -Wmain -Wundef -Wconversion -Wsign-conversion -Wunused-parameter -Wuninitialized -Wmissing-declarations -Wshadow -Wunreachable-code -Wswitch-default -Wswitch-enum -Wcast-align -Wmissing-include-dirs -Winit-self -Wfloat-equal -Wdouble-promotion -mmcu=atmega328p -mrelax -finline-functions -finline-limit=32 -fsigned-char -g -gdwarf-2 -fno-exceptions -ffunction-sections -fdata-sections -fno-rtti -fno-use-cxa-atexit -fno-exceptions -fno-threadsafe-statics -fno-enforce-eh-specs -ftemplate-depth=32 -Wzero-as-null-pointer-constant -I. -I../real-time-cpp-root/ref_app/src -I../real-time-cpp-root/ref_app/src/util/STL -DWIDE_INTEGER_DISABLE_IOSTREAM -DWIDE_INTEGER_DISABLE_TO_STRING -DWIDE_INTEGER_DISABLE_TRIVIAL_COPY_AND_STD_LAYOUT_CHECKS -DWIDE_INTEGER_DISABLE_IMPLEMENT_UTIL_DYNAMIC_ARRAY -DWIDE_INTEGER_NAMESPACE=ckormanyos -DWIDE_INTEGER_STANDALONE_${{ steps.upcase_my_example.outputs.uppercase }} examples/${{ matrix.example }}.cpp -Wl,--gc-sections -Wl,-Map,./bin/${{ matrix.example }}.map -o bin/${{ matrix.example }}.elf' avr-g++ -x c++ -std=${{ matrix.standard }} -Os -Werror -Wall -Wextra -Wpedantic -Wpedantic -Wmain -Wundef -Wconversion -Wsign-conversion -Wunused-parameter -Wuninitialized -Wmissing-declarations -Wshadow -Wunreachable-code -Wswitch-default -Wswitch-enum -Wcast-align -Wmissing-include-dirs -Winit-self -Wfloat-equal -Wdouble-promotion -mmcu=atmega328p -mrelax -finline-functions -finline-limit=32 -fsigned-char -g -gdwarf-2 -fno-exceptions -ffunction-sections -fdata-sections -fno-rtti -fno-use-cxa-atexit -fno-exceptions -fno-threadsafe-statics -fno-enforce-eh-specs -ftemplate-depth=32 -Wzero-as-null-pointer-constant -I. -I../real-time-cpp-root/ref_app/src -I../real-time-cpp-root/ref_app/src/util/STL -DWIDE_INTEGER_DISABLE_IOSTREAM -DWIDE_INTEGER_DISABLE_TO_STRING -DWIDE_INTEGER_DISABLE_TRIVIAL_COPY_AND_STD_LAYOUT_CHECKS -DWIDE_INTEGER_DISABLE_IMPLEMENT_UTIL_DYNAMIC_ARRAY -DWIDE_INTEGER_NAMESPACE=ckormanyos -DWIDE_INTEGER_STANDALONE_${{ steps.upcase_my_example.outputs.uppercase }} examples/${{ matrix.example }}.cpp -Wl,--gc-sections -Wl,-Map,./bin/${{ matrix.example }}.map -o bin/${{ matrix.example }}.elf echo echo 'run objcopy with:' echo 'avr-objcopy bin/${{ matrix.example }}.elf -O ihex bin/${{ matrix.example }}.hex' avr-objcopy bin/${{ matrix.example }}.elf -O ihex bin/${{ matrix.example }}.hex echo echo 'ls -la bin/${{ matrix.example }}.elf bin/${{ matrix.example }}.map bin/${{ matrix.example }}.hex' ls -la bin/${{ matrix.example }}.elf bin/${{ matrix.example }}.map bin/${{ matrix.example }}.hex working-directory: ./ gcc-clang-boost_backend: runs-on: ubuntu-latest defaults: run: shell: bash strategy: fail-fast: false matrix: standard: [ c++14, c++20 ] compiler: [ g++, clang++ ] steps: - uses: actions/checkout@v6 with: fetch-depth: '0' - name: clone-submods-bootstrap-headers-boost-develop run: | git clone -b develop --depth 1 https://github.com/boostorg/boost.git ../boost-root cd ../boost-root git submodule update --init tools git submodule update --init libs/assert git submodule update --init libs/config git submodule update --init libs/core git submodule update --init libs/math git submodule update --init libs/multiprecision ./bootstrap.sh ./b2 headers - name: gcc-clang-boost_backend run: | grep BOOST_VERSION ../boost-root/boost/version.hpp echo "print compiler version" ${{ matrix.compiler }} -v echo echo "compile ./test_uintwide_t_boost_backend_via_test_arithmetic.exe" ${{ matrix.compiler }} -finline-functions -m64 -O2 -Werror -Wall -Wextra -Wpedantic -Wconversion -Wsign-conversion -Wshadow -Wundef -Wunused-parameter -Wuninitialized -Wunreachable-code -Winit-self -Wzero-as-null-pointer-constant -std=${{ matrix.standard }} -I. -I../boost-root test/test_uintwide_t_boost_backend_via_test_arithmetic.cpp -o test_uintwide_t_boost_backend_via_test_arithmetic.exe echo "ls -la ./test_uintwide_t_boost_backend_via_test_arithmetic.exe" echo echo "verify presence of ./test_uintwide_t_boost_backend_via_test_arithmetic.exe" ls -la ./test_uintwide_t_boost_backend_via_test_arithmetic.exe echo echo "execute ./test_uintwide_t_boost_backend_via_test_arithmetic.exe" ./test_uintwide_t_boost_backend_via_test_arithmetic.exe gcc-clang-xtra: runs-on: ubuntu-latest defaults: run: shell: bash strategy: fail-fast: false matrix: standard: [ c++20 ] compiler: [ g++, clang++ ] suite: [ test_uintwide_t_xtra_from_issue_335 ] steps: - uses: actions/checkout@v6 with: fetch-depth: '0' - name: gcc-clang-xtra run: | echo "compile ./${{ matrix.suite }}.exe" ${{ matrix.compiler }} -v ${{ matrix.compiler }} -finline-functions -m64 -O3 -Werror -Wall -Wextra -Wpedantic -Wconversion -Wsign-conversion -Wshadow -Wundef -Wunused-parameter -Wuninitialized -Wunreachable-code -Winit-self -Wzero-as-null-pointer-constant -std=${{ matrix.standard }} -DWIDE_INTEGER_DISABLE_PRIVATE_CLASS_DATA_MEMBERS -DWIDE_INTEGER_NAMESPACE=ckormanyos -I. test/${{ matrix.suite }}.cpp -o ${{ matrix.suite }}.exe ls -la ./${{ matrix.suite }}.exe ./${{ matrix.suite }}.exe ================================================ FILE: .github/workflows/wide_integer_codecov.yml ================================================ # ------------------------------------------------------------------------------ # Copyright Christopher Kormanyos 2022 - 2026. # Distributed under the Boost Software License, # Version 1.0. (See accompanying file LICENSE_1_0.txt # or copy at http://www.boost.org/LICENSE_1_0.txt) # ------------------------------------------------------------------------------ name: wide_integer_codecov on: push: branches: - master pull_request: types: [opened, synchronize, reopened] jobs: gnumake-gcc-gcov-native: runs-on: ubuntu-latest defaults: run: shell: bash strategy: fail-fast: false matrix: standard: [ c++14 ] compiler: [ g++ ] steps: - uses: actions/checkout@v6 with: fetch-depth: '0' - name: update-tools run: sudo apt install lcov - name: clone-submods-bootstrap-headers-boost-develop run: | git clone -b develop --depth 1 https://github.com/boostorg/boost.git ../boost-root cd ../boost-root git submodule update --init tools git submodule update --init libs/config git submodule update --init libs/multiprecision ./bootstrap.sh ./b2 headers - name: gnumake-gcc-gcov-native run: | grep BOOST_VERSION ../boost-root/boost/version.hpp cd .gcov/make echo "build and run gcov/lcov/genhtml" echo "make prepare -f make_gcov_01_generic.gmk MY_ALL_COV=0 MY_BOOST_ROOT=../../../boost-root MY_CC=${{ matrix.compiler }} MY_STD=${{ matrix.standard }}" echo make prepare -f make_gcov_01_generic.gmk MY_ALL_COV=0 MY_BOOST_ROOT=../../../boost-root MY_CC=${{ matrix.compiler }} MY_STD=${{ matrix.standard }} echo echo "make gcov -f make_gcov_01_generic.gmk --jobs=8 MY_ALL_COV=0 MY_BOOST_ROOT=../../../boost-root MY_CC=${{ matrix.compiler }} MY_STD=${{ matrix.standard }}" echo make gcov -f make_gcov_01_generic.gmk --jobs=8 MY_ALL_COV=0 MY_BOOST_ROOT=../../../boost-root MY_CC=${{ matrix.compiler }} MY_STD=${{ matrix.standard }} echo echo "return to wide-integer root directory" cd ../.. - name: upload-codecov uses: codecov/codecov-action@v4 with: plugin: gcov file: ${{ runner.workspace }}/wide-integer/.gcov/make/coverage.info token: ${{ secrets.CODECOV_TOKEN }} fail_ci_if_error: true verbose: false ================================================ FILE: .github/workflows/wide_integer_fuzzing.yml ================================================ # ------------------------------------------------------------------------------ # Copyright Christopher Kormanyos 2024 - 2026. # Distributed under the Boost Software License, # Version 1.0. (See accompanying file LICENSE_1_0.txt # or copy at http://www.boost.org/LICENSE_1_0.txt) # ------------------------------------------------------------------------------ name: wide_integer_fuzzing on: push: branches: - '**' pull_request: schedule: - cron: '0 2 * * *' # run at 2:00 AM UTC jobs: clang-fuzzing: runs-on: ubuntu-latest defaults: run: shell: bash strategy: fail-fast: false matrix: compiler: [ clang++ ] steps: - uses: actions/checkout@v6 with: fetch-depth: '0' - name: update-tools run: sudo apt install llvm lld - name: clone-submods-bootstrap-headers-boost-develop run: | git clone -b develop --depth 1 https://github.com/boostorg/boost.git ../boost-root cd ../boost-root git submodule update --init tools git submodule update --init libs/config git submodule update --init libs/multiprecision ./bootstrap.sh ./b2 headers - name: clang-fuzzing run: | grep BOOST_VERSION ../boost-root/boost/version.hpp ${{ matrix.compiler }} -v echo "run fuzzing test" ./run_fuzzing.sh clang-fuzzing-versus-cppalliance-int128: runs-on: ubuntu-latest defaults: run: shell: bash strategy: fail-fast: false matrix: compiler: [ clang++ ] steps: - uses: actions/checkout@v6 with: fetch-depth: '0' - name: update-tools run: sudo apt install llvm lld - name: clone-cppalliance-int128 working-directory: ${{runner.workspace}} run: | git clone -b master --depth 1 https://github.com/cppalliance/int128.git ${{runner.workspace}}/cppalliance-int128 - name: clang-fuzzing-versus-cppalliance-int128 run: | ${{ matrix.compiler }} -v echo 'compiling test/fuzzing/test_fuzzing_div_versus_cppalliance_int128.cpp' ${{ matrix.compiler }} -std=c++20 -g -O2 -Wall -Wextra -Wpedantic -Wconversion -Wsign-conversion -fsanitize=fuzzer -I. -I${{runner.workspace}}/cppalliance-int128/include test/fuzzing/test_fuzzing_div_versus_cppalliance_int128.cpp -o test_fuzzing_div_versus_cppalliance_int128 echo "run test_fuzzing_div_versus_cppalliance_int128" rnd_seed=-seed=$(($(date +%s%N) % 4294967295)) echo echo seed is $rnd_seed echo ./test_fuzzing_div_versus_cppalliance_int128 -max_total_time=900 -max_len=32 -verbosity=0 -close_fd_mask=3 $rnd_seed ================================================ FILE: .github/workflows/wide_integer_sonar.yml ================================================ # ------------------------------------------------------------------------------ # Copyright Christopher Kormanyos 2022 - 2026. # Distributed under the Boost Software License, # Version 1.0. (See accompanying file LICENSE_1_0.txt # or copy at http://www.boost.org/LICENSE_1_0.txt) # ------------------------------------------------------------------------------ name: wide_integer_sonar on: push: branches: - master pull_request: types: [opened, synchronize, reopened] jobs: sonar-gcc-native: runs-on: ubuntu-latest steps: - uses: actions/checkout@v6 with: fetch-depth: 0 - name: clone-submods-bootstrap-headers-boost-develop run: | git clone -b develop --depth 1 https://github.com/boostorg/boost.git ../boost-root cd ../boost-root git submodule update --init tools git submodule update --init libs/config git submodule update --init libs/multiprecision ./bootstrap.sh ./b2 headers - name: Install Build Wrapper uses: SonarSource/sonarqube-scan-action/install-build-wrapper@v6.0.0 - name: Run Build Wrapper run: | build-wrapper-linux-x86-64 --out-dir ${{ runner.workspace }}/build_wrapper_output_directory g++ -finline-functions -m64 -O3 -Werror -Wall -Wextra -Wconversion -Wsign-conversion -std=c++14 -DWIDE_INTEGER_HAS_LIMB_TYPE_UINT64 -DWIDE_INTEGER_HAS_MUL_8_BY_8_UNROLL -I. -I../boost-root -pthread -lpthread test/test.cpp test/test_uintwide_t_boost_backend.cpp test/test_uintwide_t_edge_cases.cpp test/test_uintwide_t_examples.cpp test/test_uintwide_t_float_convert.cpp test/test_uintwide_t_int_convert.cpp test/test_uintwide_t_n_base.cpp test/test_uintwide_t_n_binary_ops_base.cpp test/test_uintwide_t_spot_values.cpp examples/example000_numeric_limits.cpp examples/example000a_builtin_convert.cpp examples/example001_mul_div.cpp examples/example001a_div_mod.cpp examples/example002_shl_shr.cpp examples/example003_sqrt.cpp examples/example003a_cbrt.cpp examples/example004_rootk_pow.cpp examples/example005_powm.cpp examples/example005a_pow_factors_of_p99.cpp examples/example006_gcd.cpp examples/example007_random_generator.cpp examples/example008_miller_rabin_prime.cpp examples/example008a_miller_rabin_prime.cpp examples/example008b_solovay_strassen_prime.cpp examples/example009_timed_mul.cpp examples/example009a_timed_mul_4_by_4.cpp examples/example009b_timed_mul_8_by_8.cpp examples/example010_uint48_t.cpp examples/example011_uint24_t.cpp examples/example012_rsa_crypto.cpp examples/example013_ecdsa_sign_verify.cpp examples/example014_pi_spigot_wide.cpp -o wide_integer.exe - name: SonarQube Scan uses: SonarSource/sonarqube-scan-action@v6.0.0 env: SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} with: args: > --define sonar.cfamily.compile-commands=${{ runner.workspace }}/build_wrapper_output_directory/compile_commands.json -Dsonar.organization=ckormanyos -Dsonar.projectName=wide-integer -Dsonar.projectKey=ckormanyos_wide-integer ================================================ FILE: .gitignore ================================================ .vs/ wide_integer.vcxproj.user x64/ wide_integer_vs2022.vcxproj.user ================================================ FILE: .props/Directory.Build.props ================================================ true ================================================ FILE: .tidy/make/make_tidy_01_generic.gmk ================================================ # ------------------------------------------------------------------------------ # Copyright Christopher Kormanyos 2022. # Distributed under the Boost Software License, # Version 1.0. (See accompanying file LICENSE_1_0.txt # or copy at http://www.boost.org/LICENSE_1_0.txt) # ------------------------------------------------------------------------------ PATH_MAKE = $(CURDIR) PATH_PRJ = $(PATH_MAKE)/../.. PATH_SRC = $(PATH_PRJ) PATH_TMP = $(PATH_MAKE)/tmp PATH_ERR = $(PATH_MAKE)/err CAT = cat GNUECHO = echo LS = ls MKDIR = mkdir TIDY = clang-tidy RM = rm SED = sed include make_tidy_02_files.gmk include make_tidy_03_flags.gmk FILES_ALL = $(FILES_PRJ) FILES_TIDY_TXT = $(addprefix $(PATH_TMP)/, $(notdir $(addsuffix .tidy_txt, $(FILES_ALL)))) # ------------------------------------------------------------------------------ # VPATH definition: VPATH is required for make to find the source files. # ------------------------------------------------------------------------------ VPATH := $(sort $(dir $(FILES_ALL))) # ------------------------------------------------------------------------------ # Main dependency: Run clang-tidy on all files and tidy tidy results. # ------------------------------------------------------------------------------ .PHONY: tidy tidy: $(FILES_TIDY_TXT) # Summarize tidy results @$(GNUECHO) +++ summarize clang-tidy results @$(GNUECHO) +++ concatenate $(PATH_TMP)/*.tidy_txt to $(PATH_TMP)/all.tidy_txt @$(CAT) $(PATH_TMP)/*.tidy_txt > $(PATH_TMP)/all.tidy_txt @$(GNUECHO) @$(GNUECHO) +++ verify existence of $(PATH_TMP)/all.tidy_txt @$(LS) -la $(PATH_TMP)/all.tidy_txt @$(GNUECHO) @$(GNUECHO) +++ print summary of tidy from $(PATH_TMP)/all.tidy_txt: @-$(SED) -n l $(PATH_TMP)/all.tidy_txt @$(GNUECHO) # ------------------------------------------------------------------------------ # Clean temporary files. # ------------------------------------------------------------------------------ .PHONY: prepare prepare: # creating output directories @$(GNUECHO) +++ creating output directories @-$(MKDIR) -p $(PATH_ERR) @-$(MKDIR) -p $(PATH_TMP) @$(GNUECHO) @$(GNUECHO) +++ cleaning output directories @-$(RM) -rf $(PATH_ERR)/*.tidy_err @-$(RM) -rf $(PATH_TMP)/*.tidy_txt @$(GNUECHO) @$(GNUECHO) +++ print clang-tidy version @$(TIDY) --version @$(GNUECHO) @$(GNUECHO) +++ print include paths @$(GNUECHO) $(C_INCLUDES) @$(GNUECHO) # ------------------------------------------------------------------------------ # pattern rule for clang-tidy analysis of cpp-files # ------------------------------------------------------------------------------ $(PATH_TMP)/%.tidy_txt : %.cpp @-$(GNUECHO) +++ tidying: $< @-$(TIDY) $(TIDY_FLAGS) $< -- $(CXX_FLAGS) $(C_INCLUDES) $(C_DEFINES) > $(PATH_TMP)/$(basename $(@F)).tidy_txt 2> $(PATH_ERR)/$(basename $(@F)).tidy_err @-$(GNUECHO) @-$(GNUECHO) +++ print $(PATH_ERR)/$(basename $(@F)).tidy_err @-$(SED) -n l $(PATH_ERR)/$(basename $(@F)).tidy_err @-$(GNUECHO) ================================================ FILE: .tidy/make/make_tidy_02_files.gmk ================================================ # ------------------------------------------------------------------------------ # Copyright Christopher Kormanyos 2022 - 2026. # Distributed under the Boost Software License, # Version 1.0. (See accompanying file LICENSE_1_0.txt # or copy at http://www.boost.org/LICENSE_1_0.txt) # ------------------------------------------------------------------------------ FILES_PRJ = $(PATH_SRC)/test/test_uintwide_t_edge_cases \ $(PATH_SRC)/test/test_uintwide_t_examples \ $(PATH_SRC)/test/test_uintwide_t_float_convert \ $(PATH_SRC)/test/test_uintwide_t_int_convert \ $(PATH_SRC)/test/test_uintwide_t_n_base \ $(PATH_SRC)/test/test_uintwide_t_n_binary_ops_base \ $(PATH_SRC)/test/test_uintwide_t_spot_values \ $(PATH_SRC)/examples/example000a_builtin_convert \ $(PATH_SRC)/examples/example000_numeric_limits \ $(PATH_SRC)/examples/example001_mul_div \ $(PATH_SRC)/examples/example001a_div_mod \ $(PATH_SRC)/examples/example002_shl_shr \ $(PATH_SRC)/examples/example003_sqrt \ $(PATH_SRC)/examples/example003a_cbrt \ $(PATH_SRC)/examples/example004_rootk_pow \ $(PATH_SRC)/examples/example005_powm \ $(PATH_SRC)/examples/example005a_pow_factors_of_p99 \ $(PATH_SRC)/examples/example006_gcd \ $(PATH_SRC)/examples/example007_random_generator \ $(PATH_SRC)/examples/example008_miller_rabin_prime \ $(PATH_SRC)/examples/example008a_miller_rabin_prime \ $(PATH_SRC)/examples/example008b_solovay_strassen_prime \ $(PATH_SRC)/examples/example009_timed_mul \ $(PATH_SRC)/examples/example009a_timed_mul_4_by_4 \ $(PATH_SRC)/examples/example009b_timed_mul_8_by_8 \ $(PATH_SRC)/examples/example010_uint48_t \ $(PATH_SRC)/examples/example011_uint24_t \ $(PATH_SRC)/examples/example012_rsa_crypto \ $(PATH_SRC)/examples/example013_ecdsa_sign_verify \ $(PATH_SRC)/examples/example014_pi_spigot_wide ================================================ FILE: .tidy/make/make_tidy_03_flags.gmk ================================================ # ------------------------------------------------------------------------------ # Copyright Christopher Kormanyos 2022 - 2025. # Distributed under the Boost Software License, # Version 1.0. (See accompanying file LICENSE_1_0.txt # or copy at http://www.boost.org/LICENSE_1_0.txt) # ------------------------------------------------------------------------------ BOOST_ROOT_FOR_TIDY = /mnt/c/boost/boost_1_78_0 CC = clang++ STD = c++14 ifneq ($(MY_BOOST_ROOT),) BOOST_ROOT_FOR_TIDY := $(MY_BOOST_ROOT) endif ifneq ($(MY_CC),) CC := $(MY_CC) endif ifneq ($(MY_STD),) STD := $(MY_STD) endif CXX_FLAGS = $(CC) \ -march=native \ -mtune=native \ -O3 \ -Wall \ -Wextra \ -Wconversion \ -Wsign-conversion \ -std=$(STD) C_DEFINES = WIDE_INTEGER_HAS_MUL_8_BY_8_UNROLL C_INCLUDES = $(PATH_SRC) \ $(BOOST_ROOT_FOR_TIDY) C_DEFINES :=$(addprefix -D,$(C_DEFINES)) C_INCLUDES :=$(addprefix -I,$(C_INCLUDES)) TIDY_CHECKS = "*, \ -cert-dcl58-cpp, \ -cppcoreguidelines-rvalue-reference-param-not-moved, \ -cppcoreguidelines-avoid-do-while, \ -modernize-type-traits, \ -modernize-use-constraints, \ -misc-header-include-cycle, \ -misc-include-cleaner, \ -misc-const-correctness, \ -performance-avoid-endl, \ -readability-identifier-length, \ -readability-redundant-casting, \ -altera-struct-pack-align, \ -altera-unroll-loops, \ -fuchsia-*, \ -llvmlibc-*" TIDY_FLAGS = --extra-arg-before=--driver-mode=g++ \ --header-filter=uintwide_t \ -warnings-as-errors=* \ -checks=$(TIDY_CHECKS) ================================================ FILE: CMakeLists.txt ================================================ project(wide-integer) cmake_minimum_required(VERSION 3.16.3) if (${CMAKE_CURRENT_SOURCE_DIR} STREQUAL ${CMAKE_SOURCE_DIR}) set(WIDE_INTEGER_MASTER_PROJECT ON) else() set(WIDE_INTEGER_MASTER_PROJECT OFF) endif() option(WIDE_INTEGER_ENABLE_TESTS "Enable/disable tests" ${WIDE_INTEGER_MASTER_PROJECT}) if (WIDE_INTEGER_ENABLE_TESTS) find_package(Boost) if (Boost_FOUND) include(CTest) add_subdirectory("examples") add_subdirectory("test") endif() endif() add_library(WideInteger INTERFACE) target_compile_features(WideInteger INTERFACE cxx_std_14) target_include_directories( WideInteger SYSTEM INTERFACE $ $) add_library(WideInteger::WideInteger ALIAS WideInteger) install(TARGETS WideInteger EXPORT WideIntegerTargets) install( FILES math/wide_integer/uintwide_t.h DESTINATION include/math/wide_integer/) install(EXPORT WideIntegerTargets FILE WideIntegerConfig.cmake NAMESPACE WideInteger:: DESTINATION lib/cmake/wide-integer) ================================================ FILE: LICENSE_1_0.txt ================================================ Boost Software License - Version 1.0 - August 17th, 2003 Permission is hereby granted, free of charge, to any person or organization obtaining a copy of the software and accompanying documentation covered by this license (the "Software") to use, reproduce, display, distribute, execute, and transmit the Software, and to prepare derivative works of the Software, and to permit third-parties to whom the Software is furnished to do so, all subject to the following: The copyright notices in the Software and this entire statement, including the above license grant, this restriction and the following disclaimer, must be included in all copies of the Software, in whole or in part, and all derivative works of the Software, unless such copies or derivative works are solely in the form of machine-executable object code generated by a source language processor. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: Makefile ================================================ ############################################################################### # Copyright Christopher Kormanyos 2026. # Distributed under the Boost Software License, # Version 1.0. (See accompanying file LICENSE_1_0.txt # or copy at http://www.boost.org/LICENSE_1_0.txt) # # My local machine # cd /mnt/c/Users/ckorm/Documents/Ks/PC_Software/NumericalPrograms/ExtendedNumberTypes/wide_integer # make MY_CC=g++ MY_BOOST_ROOT=/mnt/c/boost/boost_1_90_0 all # MacOS with brew llvm # make MY_CC=/opt/homebrew/opt/llvm/bin/clang++ MY_BOOST_ROOT=../boost-root MY_STD=c++23 MY_BREW=brew all all : compile_and_link BOOST_ROOT := ../boost-root CC := clang++ STD := c++20 ifneq ($(MY_BOOST_ROOT),) BOOST_ROOT := $(MY_BOOST_ROOT) endif ifneq ($(MY_CC),) CC := $(MY_CC) endif ifneq ($(MY_STD),) STD := $(MY_STD) endif ECHO := echo FILES_SRC := test/test.cpp \ test/test_uintwide_t_boost_backend.cpp \ test/test_uintwide_t_edge_cases.cpp \ test/test_uintwide_t_examples.cpp \ test/test_uintwide_t_float_convert.cpp \ test/test_uintwide_t_int_convert.cpp \ test/test_uintwide_t_n_base.cpp \ test/test_uintwide_t_n_binary_ops_base.cpp \ test/test_uintwide_t_spot_values.cpp \ examples/example000a_builtin_convert.cpp \ examples/example000_numeric_limits.cpp \ examples/example001_mul_div.cpp \ examples/example001a_div_mod.cpp \ examples/example002_shl_shr.cpp \ examples/example003_sqrt.cpp \ examples/example003a_cbrt.cpp \ examples/example004_rootk_pow.cpp \ examples/example005_powm.cpp \ examples/example005a_pow_factors_of_p99.cpp \ examples/example006_gcd.cpp \ examples/example007_random_generator.cpp \ examples/example008_miller_rabin_prime.cpp \ examples/example008a_miller_rabin_prime.cpp \ examples/example008b_solovay_strassen_prime.cpp \ examples/example009_timed_mul.cpp \ examples/example009a_timed_mul_4_by_4.cpp \ examples/example009b_timed_mul_8_by_8.cpp \ examples/example010_uint48_t.cpp \ examples/example011_uint24_t.cpp \ examples/example012_rsa_crypto.cpp \ examples/example013_ecdsa_sign_verify.cpp \ examples/example014_pi_spigot_wide.cpp CPPFLAGS := -std=$(STD) \ -finline-functions \ -march=native \ -mtune=native \ -O3 \ -Werror \ -Wall \ -Wextra \ -Wpedantic \ -Wconversion \ -Wsign-conversion \ -Wshadow \ -Wundef \ -Wunused-parameter \ -Wuninitialized \ -Wunreachable-code \ -Winit-self \ -Wzero-as-null-pointer-constant C_DEFINES := -DWIDE_INTEGER_HAS_LIMB_TYPE_UINT64 \ -DWIDE_INTEGER_HAS_MUL_8_BY_8_UNROLL \ -DWIDE_INTEGER_NAMESPACE=ckormanyos C_INCLUDES := -I. \ -I$(BOOST_ROOT) ifeq ($(MY_BREW),brew) C_INCLUDES += -isystem /opt/homebrew/opt/llvm/include C_INCLUDES += -isystem $$(xcrun --show-sdk-path) endif LDFLAGS := -pthread \ -lpthread ifeq ($(MY_BREW),brew) LDFLAGS += -L/opt/homebrew/opt/llvm/lib endif clean : @-$(ECHO) @-$(ECHO) +++ cleaning @-rm -f ./wide_integer || true compile_and_link : clean @-$(ECHO) @-$(ECHO) +++ print compiler version @-$(CC) --version @-$(ECHO) @-$(ECHO) +++ compiling and linking to wide_integer @-$(ECHO) -$(CC) $(CPPFLAGS) $(C_DEFINES) $(C_INCLUDES) $(LDFLAGS) $(FILES_SRC) -o wide_integer @-$(ECHO) @-$(ECHO) +++ check for executable wide_integer -ls -la ./wide_integer @-$(ECHO) ================================================ FILE: README.md ================================================ Wide-integer ==================

Build Status Build Status Issues CodeQL Coverity Scan Quality Gate Status code coverage Boost Software License 1.0 GitHub commit activity GitHub code size in bytes Conan Center

Wide-integer implements a generic C++ template for extended width unsigned and signed integral types. This C++ template header-only library implements drop-in big integer types such as `uint128_t`, `uint256_t`, `uint384_t`, `uint512_t`, `uint1024_t`, `uint1536_t`, etc. These can be used essentially like regular built-in integers. Corresponding _signed_ integer types such as `int128_t`, `int256_t`, and the like can also be used. The big integer class is called `math::wide_integer::uintwide_t` (i.e., `uintwide_t` residing in the `namespace` `math::wide_integer`), as shown in greater detail below. Wide-integer supports both unsigned as well as signed integral types having width of $1 {\ldots} 63 {\times} 2^N$ while being $16$, $24$, $32$ or larger. In addition, small integer types such as software-synthesized versions of `uint24_t`, `uint48_t`, `uint64_t`, `uint96_t`, `uint128_t`, etc. (or signed counterparts of these) can also be created with wide-integer. We also emphasize here that less-common types (i.e., those less common than, say, `uint128_t`, `uint256_t`, `uint512_t`, etc.) can also be synthesized. Types such as `uint80_t` made from five 16-bit limbs, or `uint96_t` composed of three 32-bit limbs, or other similar types can be readily synthesized with wide-integer. Wide-integer also features basic realizations of several elementary and number theoretical functions such as root finding, random distribution, Miller-Rabin primality testing, greatest common denominator (GCD), least common multiplier (LCM), integer division (i.e., `divmod()`) and more. Inclusion of a single C++14 header file is all that is needed for using wide-integer, as shown in the [examples](./examples). ## Implementation goals - Signed and unsigned versions of `uintwide_t` should behave as closely as possible to the behaviors of signed and unsigned versions of built-in `int`. - Relatively wide precision range from $24$, $32$, $64$ bits up to tens of thousands of bits. - Moderately good efficiency over the entire wide precision range. - Clean header-only C++14 design. - Seamless portability to any modern C++14, 17, 20, 23 compiler and beyond. - Scalability with small memory footprint and efficiency suitable for both PC/workstation systems as well as _bare-metal_ embedded systems. - C++14, 17, 20, 23 and beyond `constexpr`-ness. ## Quick start When working in your own project with wide-integer, using the [uintwide_t.h header](./math/wide_integer/uintwide_t.h) is straightforward. Identify the header within its directory. Include this header path to the compiler's set of include paths or in your project. Then simply `#include ` in the normal C++ way. Easy application follows via traditional C-style typedef or alias such as `uint512_t`. An instance of the defined type can be used very much like a built-in integral type. In the following code, for example, the static `uint512_t` variable `x` is initialized with unsigned, integral value `3U`. The `main` subroutine subsequently computes $3^{301}$ with the specialized wide-integer, namespace-specific function `pow`, which is found via ADL. The approximate result is $$3^{301}~{\approx}~4.10674{\times}~10^{143}\text{.}$$ See also the following informative links to Wolfram Alpha(R). - Query the approximate value of $3^{301}$ with [`N[3^301]`](https://www.wolframalpha.com/input?i=N%5B3%5E301%5D) - Verify the exact value of $3^{301}$ with [`3^301`](https://www.wolframalpha.com/input?i=3%5E301) This example, compiled with successful output result, is shown in its entirety in the following [short link](https://godbolt.org/z/bjxxrK1xP) to [godbolt](https://godbolt.org). In particular, ```cpp #include #include auto main() -> int { using uint512_t = ::math::wide_integer::uintwide_t<512U, std::uint32_t>; const uint512_t x { 3U }; const auto p3 = pow(x, 301); // 410674437175765127973978082146264947899391086876012309414440570235106991532497229781400618467066824164751453321793982128440538198297087323698003 std::cout << "p3: " << p3 << std::endl; std::cout << "Cast p3 to double: " << double { p3 } << std::endl; } ``` The code sequence above defines the local data type `uint512_t` with an alias. The first template parameter `512U` sets the binary width (or bit count) while the second optional template parameter `std::uint32_t` sets the internal _limb_ _type_. The limb type must be unsigned and one of `std::uint8_t`, `std::uint16_t`, `std::uint32_t` or on some systems `std::uint64_t`. If the second template parameter `LimbType` is left blank, the default limb type is thirty-two bits in width and unsigned. The complete template signature of the `uintwide_t` class is shown below. ```cpp namespace math::wide_integer { namespace detail { using size_t = std::uint32_t; } using detail::size_t; // Forward declaration of the uintwide_t template class. template class uintwide_t; } // namespace math::wide_integer ``` `uintwide_t` also has a third optional template paramter that is used to set the _allocator_ _type_ employed for internal storage of the big integer's data. The default allocator type is `void` and `uintwide_t` uses stack allocation with an `std::array`-like internal representation. Setting the allocator type to an actual allocator such as, for instance, `std::allocator` activates allocator-based internal storage for `uintwide_t`. Using allocator-based storage reduces stack consumption and can be especially beneficial for higher digit counts. For low digit counts, the allocator type can simply be left blank (thus defaulting to `void`) or explicitly be set to `void` and stack allocation will be used in either case. If an allocator is supplied with any granularity other than `limb_type` (in other words `LimbType`) such as `std::allocator`, `custom_allocator_type`, etc., then the `uintwide_t` class will internally _rebind_ the allocator to the granularity and `unsigned`-ness of `limb_type` using `rebind_alloc` from `std::allocator_traits`. The fourth template parameter `IsSigned` can be set to `true` to activate a signed integer type. If left blank, the default value of `IsSigned` is `false` and the integer type will be unsigned. ## Examples Various interesting and algorithmically challenging [examples](./examples) have been implemented. It is hoped that the examples provide inspiration and guidance on how to use wide-integer. - [example000_numeric_limits.cpp](./examples/example000_numeric_limits.cpp) verifies parts of the specializations of `std::numeric_limits` for (unsigned) `uint256_t`and (signed) `int256_t`. - [example000a_builtin_convert.cpp](./examples/example000a_builtin_convert.cpp) exercises some conversions to/from built-in types/`uintwide_t`. - [example001_mul_div.cpp](./examples/example001_mul_div.cpp) performs multiplication and division. - [example001a_div_mod.cpp](./examples/example001a_div_mod.cpp) exercises division and modulus calculations. - [example002_shl_shr.cpp](./examples/example002_shl_shr.cpp) does a few left and right shift operations. - [example003_sqrt.cpp](./examples/example003_sqrt.cpp) computes a square root. - [example003a_cbrt](./examples/example003a_cbrt.cpp) computes a cube root. - [example004_rootk_pow.cpp](./examples/example004_rootk_pow.cpp) computes an integral seventh root and its corresponding power. A negative-valued cube root is also tested. - [example005_powm.cpp](./examples/example005_powm.cpp) tests the power-modulus function `powm`. - [example005a_pow_factors_of_p99.cpp](./examples/example005a_pow_factors_of_p99.cpp) verifies a beautiful, known prime factorization result from a classic tabulated value. - [example006_gcd.cpp](./examples/example006_gcd.cpp) tests several computations of greatest common divisor using the `gcd` function. - [example007_random_generator.cpp](./examples/example007_random_generator.cpp) computes some large pseudo-random integers. - [example008_miller_rabin_prime.cpp](./examples/example008_miller_rabin_prime.cpp) implements primality testing via Miller-Rabin. - [example008a_miller_rabin_prime.cpp](./examples/example008a_miller_rabin_prime.cpp) verifies Boost's interpretation of Miller-Rabin primality testing using `uintwide_t`-based types. - [example008b_solovay_strassen_prime.cpp](./examples/example008b_solovay_strassen_prime.cpp) implements a standalone implementation of Solovay-Strassen primality testing using `uintwide_t`-based types. - [example009_timed_mul.cpp](./examples/example009_timed_mul.cpp) measures multiplication timings. - [example009a_timed_mul_4_by_4.cpp](./examples/example009a_timed_mul_4_by_4.cpp) also measures multiplication timings for the special case of wide integers having four limbs. - [example009b_timed_mul_8_by_8.cpp](./examples/example009b_timed_mul_8_by_8.cpp) measures, yet again, multiplication timings for the special case of wide integers having eight limbs. - [example010_uint48_t.cpp](./examples/example010_uint48_t.cpp) verifies 48-bit integer caluclations. - [example011_uint24_t.cpp](./examples/example011_uint24_t.cpp) performs calculations with 24-bits, which is definitely on the small side of the range of wide-integer. - [example012_rsa_crypto.cpp](./examples/example012_rsa_crypto.cpp) performs cryptographic calculations with 2048-bits, exploring a standardized test case. - [example013_ecdsa_sign_verify.cpp](./examples/example013_ecdsa_sign_verify.cpp) provides an intuitive view on elliptic-curve algebra, depicting a well-known cryptographic key-gen/sign/verify method. - [example014_pi_spigot_wide.cpp](./examples/example014_pi_spigot_wide.cpp) calculates $10,001$ decimal digits of the mathematical constant $\pi$ using a `uintwide_t`-based template spigot algorithm. ## Building ### Build Status [![Build Status](https://github.com/ckormanyos/wide-integer/actions/workflows/wide_integer.yml/badge.svg)](https://github.com/ckormanyos/wide-integer/actions) The recent status of building and executing the tests and examples in Continuous Integration (CI) is always shown in the Build Status banner. Additional banners from other syntax checks and builds may also be visible. It is also possible, if desired, to build and execute the tests and examples using various different OS/compiler combinations. ### Build with Microsoft Visual Studio Building and running the tests and examples can be accomplished using the Microsoft VisualStudio solution workspace provided in `wide_integer.sln`, `wide_integer_vs2022.sln`, etc. The MSVC solution file(s) are located in the project's root directory. ### Build with CMake You can also build and run tests and examples from an empty directory using CMake. Follow the CMake pattern: ```sh cmake /path/to/wide-integer cmake --build . ctest --verbose ``` ### Build on the *nix command line Alternatively building the tests and examples with native GCC (i.e., on *nix) can be executed with a simple, but rather lengthy, command line entered manually from the command shell. Consider, for instance, building in Linux with GCC in the presence of `unsigned` `__int128`. Furthermore, the Boost.Multiprecision library is used for some examples and tests. In this build example, Boost is intended to be located in the made-up directory `../boost-root`, which needs to be adapted according to the actual location of Boost. The command line below illustrates how to build all of the wide_integer tests and examples directly from the *nix command line. ```sh cd wide_integer g++ \ -finline-functions \ -finline-limit=32 \ -march=native \ -mtune=native \ -O3 \ -Wall \ -Wextra \ -Wpedantic \ -Wconversion \ -Wsign-conversion \ -Wno-maybe-uninitialized \ -Wno-cast-function-type \ -std=c++14 \ -DWIDE_INTEGER_HAS_LIMB_TYPE_UINT64 \ -I. \ -I../boost-root \ -pthread \ -lpthread \ test/test.cpp \ test/test_uintwide_t_boost_backend.cpp \ test/test_uintwide_t_edge_cases.cpp \ test/test_uintwide_t_examples.cpp \ test/test_uintwide_t_float_convert.cpp \ test/test_uintwide_t_int_convert.cpp \ test/test_uintwide_t_n_base.cpp \ test/test_uintwide_t_n_binary_ops_base.cpp \ test/test_uintwide_t_spot_values.cpp \ examples/example000_numeric_limits.cpp \ examples/example000a_builtin_convert.cpp \ examples/example001_mul_div.cpp \ examples/example001a_div_mod.cpp \ examples/example002_shl_shr.cpp \ examples/example003_sqrt.cpp \ examples/example003a_cbrt.cpp \ examples/example004_rootk_pow.cpp \ examples/example005_powm.cpp \ examples/example005a_pow_factors_of_p99 \ examples/example006_gcd.cpp \ examples/example007_random_generator.cpp \ examples/example008_miller_rabin_prime.cpp \ examples/example008a_miller_rabin_prime.cpp \ examples/example008b_solovay_strassen_prime \ examples/example009_timed_mul.cpp \ examples/example009a_timed_mul_4_by_4.cpp \ examples/example009b_timed_mul_8_by_8.cpp \ examples/example010_uint48_t.cpp \ examples/example011_uint24_t.cpp \ examples/example012_rsa_crypto.cpp \ examples/example013_ecdsa_sign_verify.cpp \ examples/example014_pi_spigot_wide.cpp \ -o wide_integer.exe ``` ### Build on the *nix command line via GNUmake There is straightforward GNUmake support via [Makefile](./Makefile). The Makefile supports various command-line options that allow tuning the compiler, language standard, Boost's root directory, etc. A sample command line for building the executable `wide_integer` with the Makefile is shown below. ```sh make MY_CC=clang++ MY_STD=c++23 MY_BOOST_ROOT=../boost-root all ``` ## Testing, CI and Quality Checks ### Testing Testing is definitely a big issue. A growing, supported test suite improves confidence in the library. It provides for tested, efficient functionality on the PC and workstation. The GitHub code is, as mentioned above, delivered with an affiliated MSVC project or a variety of other build/make options that use easy-to-understand subroutines called from `main()`. These exercise the various examples and the full suite of test cases. If an issue is reported, reproduced and verified, an attempt is made to correct it without breaking any other code. Upon successful correction, specific test cases exercising the reported issue are usually added as part of the issue resolution process. ### CI and Quality checks CI runs on both push-to-branch as well as pull request using GitHub Actions. Various compilers, operating systems, and C++ standards ranging from C++14, 17, 20, 23 are included in CI. In CI, we use both elevated GCC/clang compiler warnings as well as MSVC level 4 warnings active on the correspondoing platforms. For additional in-depth syntax checking, clang-tidy is used both in CI as well as in offline checks to improve static code quality. GCC's run-time [sanitizers](https://gcc.gnu.org/onlinedocs/gcc/Instrumentation-Options.html) are used in CI in order to help assure dynamic quality. This effort also includes _fuzzing_ with [libFuzzer](https://llvm.org/docs/LibFuzzer.html). Additional quality checks are performed on pull-request and merge to master using modern third party open-source services. These include [CodeQL](https://github.com/ckormanyos/wide-integer/actions?query=workflow%3ACodeQL), [Synopsis Coverity](https://scan.coverity.com/projects/ckormanyos-wide-integer), and [CodeSonar](https://sonarcloud.io/summary/new_code?id=ckormanyos_wide-integer). At the moment, the Coverity check is run with manual report submission. Automation of this is, however, planned. Code coverage uses GCC/gcov/lcov and has a quality-gate with comparison/baseline-check provided by [Codecov](https://app.codecov.io/gh/ckormanyos/wide-integer). Quality badges are displayed at the top of this repository's readme page. ## Detailed examples We will now present various straightforward detailed examples. The code below performs some elementary algebraic calculations with a simple mixture of 256-bit and 512-bit unsigned integral types. This example, compiled with successful output result, is shown in its entirety in the following [short link](https://godbolt.org/z/Gj7cEc3jc) to [godbolt](https://godbolt.org). ```cpp #include #include #include #include auto main() -> int { using uint256_t = ::math::wide_integer::uint256_t; using uint512_t = ::math::wide_integer::uint512_t; // Construction from string. Additional constructors // are available from other built-in types. const uint256_t a("0xF4DF741DE58BCB2F37F18372026EF9CBCFC456CB80AF54D53BDEED78410065DE"); const uint256_t b("0x166D63E0202B3D90ECCEAA046341AB504658F55B974A7FD63733ECF89DD0DF75"); // Elementary arithmetic operations. const uint512_t c = (uint512_t(a) * uint512_t(b)); const uint256_t d = (a / b); // Logical comparison. const auto result_is_ok = ( (c == "0x1573D6A7CEA734D99865C4F428184983CDB018B80E9CC44B83C773FBE11993E7E491A360C57EB4306C61F9A04F7F7D99BE3676AAD2D71C5592D5AE70F84AF076") && (d == "0xA")); // Print the hexadecimal representation string output. std::stringstream strm; strm << "0x" << std::hex << std::uppercase << c << '\n'; strm << "0x" << std::hex << std::uppercase << d << '\n'; // Visualize if the result is OK. strm << "result_is_ok: " << std::boolalpha << result_is_ok; std::cout << strm.str() << std::endl; } ``` Wide-integer also supports a small selection of number-theoretical functions such as least and most significant bit, square root, $k^{th}$ root, power, power-modulus, greatest common denominator and random number generation. These functions are found via ADL. The example below calculates an integer square root. This example, compiled with successful output result, is shown in its entirety in the following [short link](https://godbolt.org/z/KofWbMq8M) to [godbolt](https://godbolt.org). ```cpp #include #include #include auto main() -> int { using uint256_t = ::math::wide_integer::uint256_t; const uint256_t a("0xF4DF741DE58BCB2F37F18372026EF9CBCFC456CB80AF54D53BDEED78410065DE"); const uint256_t s = sqrt(a); const auto result_is_ok = (s == "0xFA5FE7853F1D4AD92BDF244179CA178B"); const auto flg = std::cout.flags(); std::cout << "result_is_ok: " << std::boolalpha << result_is_ok << std::endl; std::cout.flags(flg); return (result_is_ok ? 0 : -1); } ``` The following sample performs add, subtract, multiply and divide of `uint48_t`. See this example also in the following [short link](https://godbolt.org/z/hc8GWMhed) to [godbolt](https://godbolt.org). ```cpp #include #include #include #include #include auto main() -> int { using uint48_t = ::math::wide_integer::uintwide_t(UINT32_C(48)), std::uint8_t>; using distribution_type = ::math::wide_integer::uniform_int_distribution(UINT32_C(48)), typename uint48_t::limb_type>; using random_engine_type = std::linear_congruential_engine; random_engine_type generator(static_cast(UINT32_C(0xF00DCAFE))); // NOLINT(cert-msc32-c,cert-msc51-cpp,cppcoreguidelines-avoid-magic-numbers,readability-magic-numbers) distribution_type distribution; const auto a64 = static_cast(distribution(generator)); const auto b64 = static_cast(distribution(generator)); const uint48_t a(a64); const uint48_t b(b64); const uint48_t c_add = (a + b); const uint48_t c_sub = (a - b); const uint48_t c_mul = (a * b); const uint48_t c_div = (a / b); const auto result_is_ok = ( ( (c_add == static_cast((a64 + b64) & static_cast(UINT64_C(0x0000FFFFFFFFFFFF)))) && (c_sub == static_cast((a64 - b64) & static_cast(UINT64_C(0x0000FFFFFFFFFFFF)))) && (c_mul == static_cast((a64 * b64) & static_cast(UINT64_C(0x0000FFFFFFFFFFFF)))) && (c_div == static_cast((a64 / b64) & static_cast(UINT64_C(0x0000FFFFFFFFFFFF))))) && ( (static_cast(c_add) == static_cast((a64 + b64) & static_cast(UINT64_C(0x0000FFFFFFFFFFFF)))) && (static_cast(c_sub) == static_cast((a64 - b64) & static_cast(UINT64_C(0x0000FFFFFFFFFFFF)))) && (static_cast(c_mul) == static_cast((a64 * b64) & static_cast(UINT64_C(0x0000FFFFFFFFFFFF)))) && (static_cast(c_div) == static_cast((a64 / b64) & static_cast(UINT64_C(0x0000FFFFFFFFFFFF)))))); std::stringstream strm { }; strm << "result_is_ok: " << std::boolalpha << result_is_ok; std::cout << strm.str() << std::endl; } ``` The next example computes the real-valued cube root of $10^{3,333}$. The real-valued cube root of this very large unsigned integer is $10^{1,111}$. We will use the (somewhat uncommon) integral data type `uint11264_t`. Since `uint11264_t` has approximately $3,390$ decimal digits of precision, it is large enough to hold the value of $10^{3,333}$ prior to (and following) the cube root operation. See this example fully worked out at the following [short link](https://godbolt.org/z/nE1eq7h6M) to [godbolt](https://godbolt.org) ```cpp #include #include #include #include auto main() -> int { using uint11264_t = ::math::wide_integer::uintwide_t<11264U, std::uint32_t>; // Create the string '1' + 3,333 times '0', which is // equivalent to the decimal integral value 10^3333. const std::string str_a = "1" + std::string(3333U, '0'); const uint11264_t a = str_a.data(); const uint11264_t s = cbrt(a); // Create the string '1' + 1,111 times '0', which is // equivalent to the decimal integral value 10^1111. // (This is the cube root of 10^3333.) const std::string str_control = "1" + std::string(1111U, '0'); const auto result_is_ok = (s == uint11264_t(str_control.data())); std::stringstream strm { }; strm << s; strm << "\nresult_is_ok: " << std::boolalpha << result_is_ok; std::cout << strm.str() << std::endl; } ``` ## Additional details Wide-Integer has been tested with numerous compilers, for target systems ranging from eight to sixty-four bits. The library is specifically designed for efficiency with small to medium bit counts. Supported bit counts include integers $1 {\ldots} 63 {\times} 2^N$ while being $16$, $24$, $32$ or larger such as $256$, $384$, $512$, $768$, $1024$, or other less common bit counts such as $11,264$, etc. Small, medium and large bit counts are supported. Common applications might use the range of `uint128_t`, `uint256_t` or `uint512_t`. It is also possible to make software-synthesized (not very efficient) versions of `uint24_t`, `uint32_t` or `uint48_t`, which might useful for hardware prototyping or other simulation and verification needs. On the high-digit end, Karatsuba multiplication extends the high performance range to many thousands of bits. Fast long division, however, relies on a classical algorithm and sub-quadratic high-precision division is not yet implemented. Portability of the code is another key point of focus. Special care has been taken to test in certain high-performance embedded real-time programming environments. ### Configuration macros (compile-time) Various configuration features can optionally be enabled or disabled at compile time with the compiler switches: ```cpp #define WIDE_INTEGER_DISABLE_IOSTREAM #define WIDE_INTEGER_DISABLE_TO_STRING #define WIDE_INTEGER_DISABLE_FLOAT_INTEROP #define WIDE_INTEGER_DISABLE_IMPLEMENT_UTIL_DYNAMIC_ARRAY #define WIDE_INTEGER_HAS_LIMB_TYPE_UINT64 #define WIDE_INTEGER_HAS_MUL_8_BY_8_UNROLL #define WIDE_INTEGER_DISABLE_TRIVIAL_COPY_AND_STD_LAYOUT_CHECKS #define WIDE_INTEGER_NAMESPACE #define WIDE_INTEGER_DISABLE_PRIVATE_CLASS_DATA_MEMBERS #define WIDE_INTEGER_HAS_CLZ_LIMB_OPTIMIZATIONS ``` When working with even the most tiny microcontroller systems, I/O streaming can optionally be disabled with the compiler switch: ```cpp #define WIDE_INTEGER_DISABLE_IOSTREAM ``` The default setting is `WIDE_INTEGER_DISABLE_IOSTREAM` not set and I/O streaming operations are enabled. Conversion to `std::string` is supported with the specialized wide-integer, namespace-specific function `to_string`. This analagous to the standard library's `std::to_string` function, but implemented specifically for instances of `uintwide_t`. Wide-integer's local, namespace-specific `to_string` function (and the inclusion of the necessary `` header) are both deactivated with: ```cpp #define WIDE_INTEGER_DISABLE_TO_STRING ``` Interoperability with built-in floating-point types such as construct-from, cast-to, binary arithmetic with built-in floating-point types can be optionally disabled by defining: ```cpp #define WIDE_INTEGER_DISABLE_FLOAT_INTEROP ``` The default setting is `WIDE_INTEGER_DISABLE_FLOAT_INTEROP` not set and all available functions implementing construction-from, cast-to, binary arithmetic with built-in floating-point types are enabled. ```cpp #define WIDE_INTEGER_DISABLE_IMPLEMENT_UTIL_DYNAMIC_ARRAY ``` This macro disables `uintwide_t.h`'s own local implementation of the `util::dynamic_array` template class. The logic of this macro is negated. Its default setting (of being disabled itself) ensures that standalone `uintwide_t.h` is free from any additional header dependencies. The template utility class `util::dynamic_array` is used as a storage container for certain instantiations of `uintwide_t`. This macro is disabled by default and `uintwide_t.h` does actually provide its own local implementation of the `util::dynamic_array` template class. Otherwise, the header file `` must be found in the include path. When working on high-performance systems having `unsigned __int128` (an extended-width, yet non-standard data type), a 64-bit limb of type `uint64_t` can be used. Enable the 64-bit limb type on such systems with the compiler switch: ```cpp #define WIDE_INTEGER_HAS_LIMB_TYPE_UINT64 ``` or (when using GCC, clang or similar) on the compiler command line with: ```cpp -DWIDE_INTEGER_HAS_LIMB_TYPE_UINT64 ``` This macro is disabled by default. The example below, for instance, uses a 64-bit limb type on GCC or clang. ```cpp #define WIDE_INTEGER_HAS_LIMB_TYPE_UINT64 #include using uint_fast256_t = ::math::wide_integer::uintwide_t<256U, std::uint64_t>; static uint_fast256_t x = 42U; ``` Another potential optimization macro can be activated with: ```cpp #define WIDE_INTEGER_HAS_MUL_8_BY_8_UNROLL ``` This macro might improve performance on some target/compiler systems by manually unrolling the multiplication loop(s) for `uintwide_t` instances having eight limbs. This macro is disabled by default. ```cpp #define WIDE_INTEGER_DISABLE_TRIVIAL_COPY_AND_STD_LAYOUT_CHECKS ``` This macro disables compile-time checks for `std::is_trivially_copyable` and `std::is_standard_layout`. These checks provide assurance (among other attributes) that `uintwide_t`'s constructors satisfy rules needed for mixed-language C/C++ usage. Some older legacy target/compiler systems might have non-standard or incomplete STL implementations that lack these compile-time templates. For such compilers, it makes sense to deactivate these compile-time checks via activation of this macro. This macro is disabled by default and both the trivially-copyable as well as the standard-layout compile-time checks are active. ```cpp #define WIDE_INTEGER_NAMESPACE something_unique ``` This is an advanced macro intended to be used in strict, exacting applications for which using the unqualified, global namespace `math` (i.e., `namespace` `::math`) is undesired or inacceptable. We recall that all parts of the wide-integer implementation, such as the `uintwide_t` class and its associated implementation details reside within `namespace` `::math::wide_integer` Defining the macro `WIDE_INTEGER_NAMESPACE` to be something like, for instance, ```sh -DWIDE_INTEGER_NAMESPACE=something_unique ``` places all parts of the wide-integer implementation and its details within the prepended outer namespace `something_unique` - as in ```cpp namespace something_unique::math::wide_integer { // ... } ``` When utilizing the `WIDE_INTEGER_NAMESPACE` option, the actual name or nesting depth of the desired prepended outer namespace can be varied if (or as) needed for the particular project. By default the macro `WIDE_INTEGER_NAMESPACE` is not defined. In this default state, `namespace` `::math::wide_integer` is used and the `uintwide_t` class and its associated implementation details reside therein. ```cpp #define WIDE_INTEGER_DISABLE_PRIVATE_CLASS_DATA_MEMBERS ``` This optional macro can be used to switch `uintwide_t`'s data member access from _private_ to _public_. This allows the `uintwide_t` class to be used as a so-called _structured_ class, such as is needed for constant-valued template parameters in a `constexpr` context. This preprocessor switch was invented based on the discussion in [issue 335](https://github.com/ckormanyos/wide-integer/issues/335) Making private data members public is unusual for some designs. So the preprocessor switch `WIDE_INTEGER_DISABLE_PRIVATE_CLASS_DATA_MEMBERS` is not defined (i.e., not set) by default. This ensures that `uintwide_t`'s data members remain private by default. ```cpp #define WIDE_INTEGER_HAS_CLZ_LIMB_OPTIMIZATIONS ``` This optional macro activates certain optimizations that count leading zero-limbs prior to classical quadratic multiplication. This may offer performance advantages on some systems by avoiding some potentially costly zero-valued limb-multiplication steps. This preprocessor switch was motivated by the discussion in [issue 362](https://github.com/ckormanyos/wide-integer/issues/362) By default, the preprocessor switch `WIDE_INTEGER_HAS_CLZ_LIMB_OPTIMIZATIONS` is not defined and CLZ-limb optimizations are default-_disabled_. ### C++14, 17, 20, 23 and beyond `constexpr` support `uintwide_t` supports C++14, 17, 20, 23 and beyond compile-time `constexpr`-ness for all constructions, casts, operations, evaluation of function results, etc. The code below, for instance, shows compile-time instantiations of `uintwide_t` from character strings with subsequent `constexpr` evaluations of binary operations multiply, divide, intergal cast and comparison. See this example fully worked out at the following [short link](https://godbolt.org/z/avWGasbdj) to [godbolt](https://godbolt.org). The generated assembly includes nothing other than the call to `main()` and its subsequent `return` of the value zero (i.e., `main()`'s successful return-value in this example). ```cpp #include using uint256_t = ::math::wide_integer::uintwide_t<256U>; using uint512_t = ::math::wide_integer::uintwide_t<512U>; // Compile-time construction from string. constexpr auto a = uint256_t("0xF4DF741DE58BCB2F37F18372026EF9CBCFC456CB80AF54D53BDEED78410065DE"); constexpr auto b = uint256_t("0x166D63E0202B3D90ECCEAA046341AB504658F55B974A7FD63733ECF89DD0DF75"); // Compile time binary arithmetic operations. constexpr auto c = uint512_t(a) * uint512_t(b); constexpr auto d = uint256_t(a / b); // Compile-time comparison. constexpr auto result_is_ok = ( (c == "0x1573D6A7CEA734D99865C4F428184983CDB018B80E9CC44B83C773FBE11993E7E491A360C57EB4306C61F9A04F7F7D99BE3676AAD2D71C5592D5AE70F84AF076") && (static_cast(d) == static_cast(UINT8_C(10)))); // constexpr verification. static_assert(result_is_ok, "Error: example is not OK!"); auto main() -> int { } ``` ### Signed integer support Signed big integers are also supported in the wide_integer library. Use the fourth template partameter `IsSigned` to indicate the signed-_ness_ (or unsigned-_ness_) of `uintwide_t`. The code below, for instance, uses an aliased version of signed `int256_t`. ```cpp #include using int256_t = ::math::wide_integer::uintwide_t<256U, std::uint32_t, void, true>; const int256_t n1(-3); const int256_t n2(-3); // +9 const int256_t n3 = n1 * n2; ``` ### Negative arguments in number theoretical functions The following design choices have been implemented when handling negative arguments in number theoretical functions. - Right shift by `n` bits via `operator>>(n)` performs a so-called _arithmetic_ right shift (ASHR). For signed integers having negative value, right-shift continually fills the sign bit with 1 while shifting right. The result is similar to signed division and closely mimics common compiler behavior for right-shift of negative-valued built-in signed `int`. - `sqrt` of `x` negative returns zero. - `cbrt` of `x` nexative integer returns `-cbrt(-x)`. - $k^{th}$ root of `x` negative returns zero unless the cube root is being computed, in which case `-cbrt(-x)` is returned. - GCD and LCM of `a`, `b` signed convert both arguments to positive and negate the result for `a`, `b` having opposite signs. - Miller-Rabin primality testing treats negative inetegers as positive when testing for prime, thus extending the set of primes to negative integers. - MSB/LSB (most/least significant bit) do not differentiate between positive or negative argument such that MSB of a negative integer will be the highest bit of the corresponding unsigned type. - Printing both positive-valued and negative-valued signed integers in hexadecimal format is supported. When printing negative-valued, signed `uintwide_t` in hexadecimal format, the sign bit and all other bits are treated as if the integer were unsigned. The negative sign is not explicitly shown when using hexadecimal format, even if the underlying integer is signed and negative-valued. A potential positive sign, however, will be shown for positive-valued signed integers in hexadecimal form in the presence of `std::showpos`. - Signed integer division and modulus results obtained from the `divmod()` function follow established number-theoretical rounding conventions, which are the same as those used by the `//`-operator in Python-3 (i.e., the same as Python-3's built-in `divmod()` function). These conventions also match those used by Mathematica(R)'s `QuotientRemainder[]` function. ## Further details ### Notable construction/conversion rules The following notable construction/conversion rules have been implemented in the wide-integer project. - Constructions-from built-in types are implicit. These are considered widening conversions. - Casts to built-in types are explicit and considered narrowing, regardless of the widths of left-and-right hand sides of the conversion. - All of both constructions-from as well as casts-to wider/less-wide and signed/unsigned wide-integer types are implicit (even if the conversion at hand is narrowing via having fewer bits). Casts such as `int128_t` to/from `uint160_t` and similar, for instance, are implicit. - All wide-integer-types are move constructable. - All wide-integer types having the same widths and having the same limb-type (but possibly different sign) are move-assignable and `std::move()`-capable. ### Importing and exporting characters and bits For sufficiently modern standards-conforming compilers, namespace-specific functions `to_chars()` and `from_chars()` are available. These each have the _usual_ ``-like behavior, known from C++17. For motivational words on `to_chars()` and `from_chars()`, see also [issue 153](https://github.com/ckormanyos/wide-integer/issues/153) and [issue 398](https://github.com/ckormanyos/wide-integer/issues/398). Support for importing and exporting bits is granted by the subroutines `import_bits()` and `export_bits()`. Their interfaces, input/output forms and constraints are intended to be identical with those used in [Boost's import/export-bits functions](https://www.boost.org/doc/libs/1_90_0/libs/multiprecision/doc/html/boost_multiprecision/tut/import_export.html). ### Alternatives and limitations Alternative libraries for big integral types include, among others, most notably [GMP](https://gmplib.org/) and [`Boost.Multiprecision`](https://www.boost.org/doc/libs/1_90_0/libs/multiprecision/doc/html/index.html). At the moment, the digit range of wide-integer is limited to the granularity of the full limb type. This means that less-common bit counts requiring the use of non-full limbs are not supported. It is **not** possible with this library, for instance, to synthesize, let's say, a 61-bit integral type. This can have performance impact. If you would like to synthesize an 80-bit integral type, for example, this can be done, but at the cost of using five 16-bit limbs. This degrades performance due to the higher limb count. This phenomenon was discussed in [issue 234](https://github.com/ckormanyos/wide-integer/issues/234) ================================================ FILE: boost/multiprecision/uintwide_t_backend.hpp ================================================ /////////////////////////////////////////////////////////////////// // Copyright Christopher Kormanyos 2019 - 2026. // // Distributed under the Boost Software License, // // Version 1.0. (See accompanying file LICENSE_1_0.txt // // or copy at http://www.boost.org/LICENSE_1_0.txt) // /////////////////////////////////////////////////////////////////// #ifndef UINTWIDE_T_BACKEND_2019_12_15_HPP // NOLINT(llvm-header-guard) #define UINTWIDE_T_BACKEND_2019_12_15_HPP #include #include #include #include #include #include #include #include #if !defined(BOOST_VERSION) #error BOOST_VERSION is not defined. Ensure that is properly included. #endif #if ((BOOST_VERSION >= 107900) && !defined(BOOST_MP_STANDALONE)) #define BOOST_MP_STANDALONE #endif #if ((BOOST_VERSION >= 108000) && !defined(BOOST_NO_EXCEPTIONS)) #define BOOST_NO_EXCEPTIONS #endif #if (BOOST_VERSION < 108000) #if defined(__GNUC__) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wconversion" #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wsign-conversion" #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wunused-parameter" #endif #endif #if (defined(__GNUC__) && !defined(__clang__) && (__GNUC__ >= 12)) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wrestrict" #endif #if (BOOST_VERSION < 108000) #if ((defined(__clang__) && (__clang_major__ > 9)) && !defined(__APPLE__)) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wdeprecated-copy" #endif #endif #if (BOOST_VERSION < 107900) #include #endif #include #include #if(__cplusplus >= 201703L) namespace boost::multiprecision { #else namespace boost { namespace multiprecision { // NOLINT(modernize-concat-nested-namespaces) #endif // Forward declaration of the uintwide_t_backend multiple precision class. // This class binds native (WIDE_INTEGER_NAMESPACE)::math::wide_integer::uintwide_t // to boost::multiprecsion::uintwide_t_backend. template< #if defined(WIDE_INTEGER_NAMESPACE) const WIDE_INTEGER_NAMESPACE::math::wide_integer::size_t MyWidth2, #else const ::math::wide_integer::size_t MyWidth2, #endif typename MyLimbType = std::uint32_t, typename MyAllocatorType = void> class uintwide_t_backend; // Define the number category as an integer number kind // for the uintwide_t_backend. This is needed for properly // interacting as a backend with boost::muliprecision. #if (BOOST_VERSION <= 107200) template< #if defined(WIDE_INTEGER_NAMESPACE) const WIDE_INTEGER_NAMESPACE::math::wide_integer::size_t MyWidth2, #else const ::math::wide_integer::size_t MyWidth2, #endif typename MyLimbType, typename MyAllocatorType> struct number_category> : public boost::mpl::int_ { }; #elif (BOOST_VERSION <= 107500) template< #if defined(WIDE_INTEGER_NAMESPACE) const WIDE_INTEGER_NAMESPACE::math::wide_integer::size_t MyWidth2, #else const ::math::wide_integer::size_t MyWidth2, #endif typename MyLimbType, typename MyAllocatorType> struct number_category> : public boost::integral_constant { }; #else template< #if defined(WIDE_INTEGER_NAMESPACE) const WIDE_INTEGER_NAMESPACE::math::wide_integer::size_t MyWidth2, #else const ::math::wide_integer::size_t MyWidth2, #endif typename MyLimbType, typename MyAllocatorType> struct number_category> : public std::integral_constant { }; #endif // This is the uintwide_t_backend multiple precision class. template< #if defined(WIDE_INTEGER_NAMESPACE) const WIDE_INTEGER_NAMESPACE::math::wide_integer::size_t MyWidth2, #else const ::math::wide_integer::size_t MyWidth2, #endif typename MyLimbType, typename MyAllocatorType> class uintwide_t_backend // NOLINT(cppcoreguidelines-special-member-functions,hicpp-special-member-functions) { public: using representation_type = #if defined(WIDE_INTEGER_NAMESPACE) WIDE_INTEGER_NAMESPACE::math::wide_integer::uintwide_t; #else ::math::wide_integer::uintwide_t; #endif #if (BOOST_VERSION <= 107500) using signed_types = mpl::list; using unsigned_types = mpl::list; using float_types = mpl::list; #else using signed_types = std::tuple< signed char, signed short, signed int, signed long, signed long long, std::intmax_t>; // NOLINT(google-runtime-int) using unsigned_types = std::tuple; // NOLINT(google-runtime-int) using float_types = std::tuple; #endif constexpr uintwide_t_backend() : m_value() { } explicit constexpr uintwide_t_backend(const representation_type& rep) : m_value(std::move(rep)) { } constexpr uintwide_t_backend(const uintwide_t_backend& other) : m_value(other.m_value) { } constexpr uintwide_t_backend(uintwide_t_backend&& other) noexcept : m_value(static_cast(other.m_value)) { } template::value) && (std::is_unsigned::value))> const* = nullptr> constexpr uintwide_t_backend(UnsignedIntegralType u) : m_value(representation_type(static_cast(u))) { } // NOLINT(google-explicit-constructor,hicpp-explicit-conversions) template::value) && (std::is_signed ::value))> const* = nullptr> constexpr uintwide_t_backend(SignedIntegralType n) : m_value(representation_type(static_cast(n))) { } // NOLINT(google-explicit-constructor,hicpp-explicit-conversions) template::value> const* = nullptr> constexpr uintwide_t_backend(FloatingPointType f) : m_value(representation_type(static_cast(f))) { } // NOLINT(google-explicit-constructor,hicpp-explicit-conversions) explicit constexpr uintwide_t_backend(const char* p_cstr) : m_value(p_cstr) { } explicit constexpr uintwide_t_backend(const std::string& str) : m_value(str) { } //constexpr ~uintwide_t_backend() = default; constexpr auto operator=(const uintwide_t_backend& other) -> uintwide_t_backend& // NOLINT(cert-oop54-cpp) { if(this != &other) { m_value.representation() = other.m_value.crepresentation(); } return *this; } constexpr auto operator=(uintwide_t_backend&& other) noexcept -> uintwide_t_backend& { m_value = static_cast(other.m_value); return *this; } template::value> const* = nullptr> constexpr auto operator=(const ArithmeticType& x) -> uintwide_t_backend& { m_value = representation_type(x); return *this; } constexpr auto operator=(const std::string& str_rep) -> uintwide_t_backend& { m_value = representation_type(str_rep); return *this; } constexpr auto operator=(const char* char_ptr) -> uintwide_t_backend& { m_value = representation_type(char_ptr); return *this; } constexpr auto swap(uintwide_t_backend& other) noexcept -> void { m_value.representation().swap(other.m_value.representation()); } constexpr auto swap(uintwide_t_backend&& other) noexcept -> void { auto tmp = std::move(m_value.representation()); m_value.representation() = std::move(other.m_value.representation()); other.m_value.representation() = std::move(tmp); } constexpr auto representation() -> representation_type& { return m_value; } WIDE_INTEGER_NODISCARD constexpr auto representation() const -> const representation_type& { return m_value; } WIDE_INTEGER_NODISCARD constexpr auto crepresentation() const -> const representation_type& { return m_value; } WIDE_INTEGER_NODISCARD auto str(std::streamsize number_of_digits, const std::ios::fmtflags format_flags) const -> std::string { static_cast(number_of_digits); // Use simple vector dynamic memory here. When using uintwide_t as a // Boost.Multiprecision number backend, we assume vector is available. std::vector pstr ( static_cast::size_type>(representation_type::wr_string_max_buffer_size_dec()) ); const auto base_rep = static_cast(((format_flags & std::ios::hex) != 0) ? 16U : 10U); const auto show_base = ((format_flags & std::ios::showbase) != 0); const auto show_pos = ((format_flags & std::ios::showpos) != 0); const auto is_uppercase = ((format_flags & std::ios::uppercase) != 0); const auto wr_string_is_ok = m_value.wr_string(pstr.data(), base_rep, show_base, show_pos, is_uppercase); return (wr_string_is_ok ? std::string(pstr.data()) : std::string()); } constexpr auto negate() -> void { m_value.negate(); } // LCOV_EXCL_LINE WIDE_INTEGER_NODISCARD constexpr auto compare(const uintwide_t_backend& other_mp_cpp_backend) const -> int { return static_cast(m_value.compare(other_mp_cpp_backend.crepresentation())); } template::value> const* = nullptr> WIDE_INTEGER_NODISCARD constexpr auto compare(ArithmeticType x) const -> int { return static_cast(m_value.compare(representation_type(x))); } WIDE_INTEGER_NODISCARD constexpr auto hash() const -> std::size_t { auto result = static_cast(0U); #if (BOOST_VERSION < 107800) using boost::hash_combine; #else using boost::multiprecision::detail::hash_combine; #endif for(auto i = static_cast(0U); i < crepresentation().crepresentation().size(); ++i) { hash_combine(result, crepresentation().crepresentation()[i]); } return result; } auto operator=(const representation_type&) -> uintwide_t_backend& = delete; private: representation_type m_value; // NOLINT(readability-identifier-naming) }; template< #if defined(WIDE_INTEGER_NAMESPACE) const WIDE_INTEGER_NAMESPACE::math::wide_integer::size_t MyWidth2, #else const ::math::wide_integer::size_t MyWidth2, #endif typename MyLimbType, typename MyAllocatorType> constexpr auto eval_add(uintwide_t_backend& result, const uintwide_t_backend& x) -> void { result.representation() += x.crepresentation(); } template< #if defined(WIDE_INTEGER_NAMESPACE) const WIDE_INTEGER_NAMESPACE::math::wide_integer::size_t MyWidth2, #else const ::math::wide_integer::size_t MyWidth2, #endif typename MyLimbType, typename MyAllocatorType> constexpr auto eval_subtract(uintwide_t_backend& result, const uintwide_t_backend& x) -> void { result.representation() -= x.crepresentation(); } template< #if defined(WIDE_INTEGER_NAMESPACE) const WIDE_INTEGER_NAMESPACE::math::wide_integer::size_t MyWidth2, #else const ::math::wide_integer::size_t MyWidth2, #endif typename MyLimbType, typename MyAllocatorType> constexpr auto eval_multiply(uintwide_t_backend& result, const uintwide_t_backend& x) -> void { result.representation() *= x.crepresentation(); } // LCOV_EXCL_LINE template< #if defined(WIDE_INTEGER_NAMESPACE) const WIDE_INTEGER_NAMESPACE::math::wide_integer::size_t MyWidth2, #else const ::math::wide_integer::size_t MyWidth2, #endif typename MyLimbType, typename MyAllocatorType, typename IntegralType, std::enable_if_t<(std::is_integral::value)> const* = nullptr> constexpr auto eval_multiply(uintwide_t_backend& result, const IntegralType& n) -> void { result.representation() *= n; } template< #if defined(WIDE_INTEGER_NAMESPACE) const WIDE_INTEGER_NAMESPACE::math::wide_integer::size_t MyWidth2, #else const ::math::wide_integer::size_t MyWidth2, #endif typename MyLimbType, typename MyAllocatorType> constexpr auto eval_divide(uintwide_t_backend& result, const uintwide_t_backend& x) -> void { result.representation() /= x.crepresentation(); } template< #if defined(WIDE_INTEGER_NAMESPACE) const WIDE_INTEGER_NAMESPACE::math::wide_integer::size_t MyWidth2, #else const ::math::wide_integer::size_t MyWidth2, #endif typename MyLimbType, typename MyAllocatorType, typename IntegralType, std::enable_if_t<( (std::is_integral ::value) && (std::is_unsigned ::value) && (std::numeric_limits::digits <= std::numeric_limits::digits))> const* = nullptr> constexpr auto eval_divide(uintwide_t_backend& result, const IntegralType& n) -> void { using local_wide_integer_type = typename uintwide_t_backend::representation_type; using local_limb_type = typename local_wide_integer_type::limb_type; result.representation().eval_divide_by_single_limb(static_cast(n), 0U, nullptr); } template< #if defined(WIDE_INTEGER_NAMESPACE) const WIDE_INTEGER_NAMESPACE::math::wide_integer::size_t MyWidth2, #else const ::math::wide_integer::size_t MyWidth2, #endif typename MyLimbType, typename MyAllocatorType, typename IntegralType, std::enable_if_t<( (std::is_integral ::value) && (std::is_unsigned ::value) && (std::numeric_limits::digits) > std::numeric_limits::digits)> const* = nullptr> constexpr auto eval_divide(uintwide_t_backend& result, const IntegralType& n) -> void { result.representation() /= n; } template< #if defined(WIDE_INTEGER_NAMESPACE) const WIDE_INTEGER_NAMESPACE::math::wide_integer::size_t MyWidth2, #else const ::math::wide_integer::size_t MyWidth2, #endif typename MyLimbType, typename MyAllocatorType> constexpr auto eval_modulus(uintwide_t_backend& result, const uintwide_t_backend& x) -> void { result.representation() %= x.crepresentation(); } template< #if defined(WIDE_INTEGER_NAMESPACE) const WIDE_INTEGER_NAMESPACE::math::wide_integer::size_t MyWidth2, #else const ::math::wide_integer::size_t MyWidth2, #endif typename MyLimbType, typename MyAllocatorType, typename IntegralType, std::enable_if_t<( (std::is_integral ::value) && (std::is_unsigned ::value) && (std::numeric_limits::digits <= std::numeric_limits::digits))> const* = nullptr> constexpr auto eval_integer_modulus(uintwide_t_backend& x, const IntegralType& n) -> IntegralType { using local_wide_integer_type = typename uintwide_t_backend::representation_type; typename uintwide_t_backend::representation_type rem; local_wide_integer_type(x.crepresentation()).eval_divide_by_single_limb(n, 0U, &rem); return static_cast(rem); } template< #if defined(WIDE_INTEGER_NAMESPACE) const WIDE_INTEGER_NAMESPACE::math::wide_integer::size_t MyWidth2, #else const ::math::wide_integer::size_t MyWidth2, #endif typename MyLimbType, typename MyAllocatorType, typename IntegralType, std::enable_if_t<( (std::is_integral ::value) && (std::is_unsigned ::value) && (std::numeric_limits::digits) > std::numeric_limits::digits)> const* = nullptr> constexpr auto eval_integer_modulus(uintwide_t_backend& x, const IntegralType& n) -> IntegralType { const uintwide_t_backend rem = x.crepresentation() % uintwide_t_backend(n); return static_cast(rem); } template< #if defined(WIDE_INTEGER_NAMESPACE) const WIDE_INTEGER_NAMESPACE::math::wide_integer::size_t MyWidth2, #else const ::math::wide_integer::size_t MyWidth2, #endif typename MyLimbType, typename MyAllocatorType> constexpr auto eval_bitwise_and(uintwide_t_backend& result, const uintwide_t_backend& x) -> void { result.representation() &= x.crepresentation(); } template< #if defined(WIDE_INTEGER_NAMESPACE) const WIDE_INTEGER_NAMESPACE::math::wide_integer::size_t MyWidth2, #else const ::math::wide_integer::size_t MyWidth2, #endif typename MyLimbType, typename MyAllocatorType> constexpr auto eval_bitwise_or( uintwide_t_backend& result, const uintwide_t_backend& x) -> void { result.representation() |= x.crepresentation(); } template< #if defined(WIDE_INTEGER_NAMESPACE) const WIDE_INTEGER_NAMESPACE::math::wide_integer::size_t MyWidth2, #else const ::math::wide_integer::size_t MyWidth2, #endif typename MyLimbType, typename MyAllocatorType> constexpr auto eval_bitwise_xor(uintwide_t_backend& result, const uintwide_t_backend& x) -> void { result.representation() ^= x.crepresentation(); } template< #if defined(WIDE_INTEGER_NAMESPACE) const WIDE_INTEGER_NAMESPACE::math::wide_integer::size_t MyWidth2, #else const ::math::wide_integer::size_t MyWidth2, #endif typename MyLimbType, typename MyAllocatorType> constexpr auto eval_complement( uintwide_t_backend& result, const uintwide_t_backend& x) -> void { using local_limb_array_type = typename uintwide_t_backend::representation_type::representation_type; using local_size_type = typename local_limb_array_type::size_type; for(auto i = static_cast(0U); i < result.crepresentation().crepresentation().size(); ++i) { using local_value_type = typename local_limb_array_type::value_type; result.representation().representation()[i] = static_cast ( ~x.crepresentation().crepresentation()[i] ); } } template< #if defined(WIDE_INTEGER_NAMESPACE) const WIDE_INTEGER_NAMESPACE::math::wide_integer::size_t MyWidth2, #else const ::math::wide_integer::size_t MyWidth2, #endif typename MyLimbType, typename MyAllocatorType> constexpr auto eval_powm( uintwide_t_backend& result, const uintwide_t_backend& b, const uintwide_t_backend& p, const uintwide_t_backend& m) -> void { result.representation() = powm(b.crepresentation(), p.crepresentation(), m.crepresentation()); } template< #if defined(WIDE_INTEGER_NAMESPACE) const WIDE_INTEGER_NAMESPACE::math::wide_integer::size_t MyWidth2, #else const ::math::wide_integer::size_t MyWidth2, #endif typename MyLimbType, typename MyAllocatorType, typename OtherIntegralTypeM, std::enable_if_t<(std::is_integral::value)> const* = nullptr> constexpr auto eval_powm( uintwide_t_backend& result, const uintwide_t_backend& b, const uintwide_t_backend& p, const OtherIntegralTypeM m) -> void { result.representation() = powm(b.crepresentation(), p.crepresentation(), m); } template< #if defined(WIDE_INTEGER_NAMESPACE) const WIDE_INTEGER_NAMESPACE::math::wide_integer::size_t MyWidth2, #else const ::math::wide_integer::size_t MyWidth2, #endif typename MyLimbType, typename MyAllocatorType, typename IntegralType, std::enable_if_t<(std::is_integral::value)> const* = nullptr> constexpr auto eval_left_shift(uintwide_t_backend& result, const IntegralType& n) -> void { result.representation() <<= n; } template< #if defined(WIDE_INTEGER_NAMESPACE) const WIDE_INTEGER_NAMESPACE::math::wide_integer::size_t MyWidth2, #else const ::math::wide_integer::size_t MyWidth2, #endif typename MyLimbType, typename MyAllocatorType, typename IntegralType, std::enable_if_t<(std::is_integral::value)> const* = nullptr> constexpr auto eval_right_shift(uintwide_t_backend& result, const IntegralType& n) -> void { result.representation() >>= n; } template< #if defined(WIDE_INTEGER_NAMESPACE) const WIDE_INTEGER_NAMESPACE::math::wide_integer::size_t MyWidth2, #else const ::math::wide_integer::size_t MyWidth2, #endif typename MyLimbType, typename MyAllocatorType> constexpr auto eval_lsb(const uintwide_t_backend& a) -> unsigned { return static_cast(lsb(a.crepresentation())); } template< #if defined(WIDE_INTEGER_NAMESPACE) const WIDE_INTEGER_NAMESPACE::math::wide_integer::size_t MyWidth2, #else const ::math::wide_integer::size_t MyWidth2, #endif typename MyLimbType, typename MyAllocatorType> constexpr auto eval_msb(const uintwide_t_backend& a) -> unsigned { return static_cast(msb(a.crepresentation())); } template< #if defined(WIDE_INTEGER_NAMESPACE) const WIDE_INTEGER_NAMESPACE::math::wide_integer::size_t MyWidth2, #else const ::math::wide_integer::size_t MyWidth2, #endif typename MyLimbType, typename MyAllocatorType> constexpr auto eval_eq(const uintwide_t_backend& a, const uintwide_t_backend& b) -> bool { return (a.compare(b) == 0); } template< #if defined(WIDE_INTEGER_NAMESPACE) const WIDE_INTEGER_NAMESPACE::math::wide_integer::size_t MyWidth2, #else const ::math::wide_integer::size_t MyWidth2, #endif typename MyLimbType, typename MyAllocatorType, typename ArithmeticType, std::enable_if_t<(std::is_arithmetic ::value)> const* = nullptr> constexpr auto eval_eq(const uintwide_t_backend& a, ArithmeticType b) -> bool { return (a.compare(b) == 0); } template< #if defined(WIDE_INTEGER_NAMESPACE) const WIDE_INTEGER_NAMESPACE::math::wide_integer::size_t MyWidth2, #else const ::math::wide_integer::size_t MyWidth2, #endif typename MyLimbType, typename MyAllocatorType, typename ArithmeticType, std::enable_if_t<(std::is_arithmetic ::value)> const* = nullptr> constexpr auto eval_eq( ArithmeticType a, const uintwide_t_backend& b) -> bool { return (uintwide_t_backend(a).compare(b) == 0); } template< #if defined(WIDE_INTEGER_NAMESPACE) const WIDE_INTEGER_NAMESPACE::math::wide_integer::size_t MyWidth2, #else const ::math::wide_integer::size_t MyWidth2, #endif typename MyLimbType, typename MyAllocatorType> constexpr auto eval_gt(const uintwide_t_backend& a, const uintwide_t_backend& b) -> bool { return (a.compare(b) == 1); } template< #if defined(WIDE_INTEGER_NAMESPACE) const WIDE_INTEGER_NAMESPACE::math::wide_integer::size_t MyWidth2, #else const ::math::wide_integer::size_t MyWidth2, #endif typename MyLimbType, typename MyAllocatorType, typename ArithmeticType, std::enable_if_t<(std::is_arithmetic ::value)> const* = nullptr> constexpr auto eval_gt(const uintwide_t_backend& a, ArithmeticType b) -> bool { return (a.compare(b) == 1); } template< #if defined(WIDE_INTEGER_NAMESPACE) const WIDE_INTEGER_NAMESPACE::math::wide_integer::size_t MyWidth2, #else const ::math::wide_integer::size_t MyWidth2, #endif typename MyLimbType, typename MyAllocatorType, typename ArithmeticType, std::enable_if_t<(std::is_arithmetic ::value)> const* = nullptr> constexpr auto eval_gt( ArithmeticType a, const uintwide_t_backend& b) -> bool { return (uintwide_t_backend(a).compare(b) == 1); } template< #if defined(WIDE_INTEGER_NAMESPACE) const WIDE_INTEGER_NAMESPACE::math::wide_integer::size_t MyWidth2, #else const ::math::wide_integer::size_t MyWidth2, #endif typename MyLimbType, typename MyAllocatorType> constexpr auto eval_lt(const uintwide_t_backend& a, const uintwide_t_backend& b) -> bool { return (a.compare(b) == -1); } template< #if defined(WIDE_INTEGER_NAMESPACE) const WIDE_INTEGER_NAMESPACE::math::wide_integer::size_t MyWidth2, #else const ::math::wide_integer::size_t MyWidth2, #endif typename MyLimbType, typename MyAllocatorType, typename ArithmeticType, std::enable_if_t<(std::is_arithmetic ::value)> const* = nullptr> constexpr auto eval_lt(const uintwide_t_backend& a, ArithmeticType b) -> bool { return (a.compare(b) == -1); } template< #if defined(WIDE_INTEGER_NAMESPACE) const WIDE_INTEGER_NAMESPACE::math::wide_integer::size_t MyWidth2, #else const ::math::wide_integer::size_t MyWidth2, #endif typename MyLimbType, typename MyAllocatorType, typename ArithmeticType, std::enable_if_t<(std::is_arithmetic ::value)> const* = nullptr> constexpr auto eval_lt( ArithmeticType a, const uintwide_t_backend& b) -> bool { return (uintwide_t_backend(a).compare(b) == -1); } template< #if defined(WIDE_INTEGER_NAMESPACE) const WIDE_INTEGER_NAMESPACE::math::wide_integer::size_t MyWidth2, #else const ::math::wide_integer::size_t MyWidth2, #endif typename MyLimbType, typename MyAllocatorType> constexpr auto eval_is_zero(const uintwide_t_backend& x) -> bool { return (x.crepresentation().is_zero()); } template< #if defined(WIDE_INTEGER_NAMESPACE) const WIDE_INTEGER_NAMESPACE::math::wide_integer::size_t MyWidth2, #else const ::math::wide_integer::size_t MyWidth2, #endif typename MyLimbType, typename MyAllocatorType> constexpr auto eval_get_sign(const uintwide_t_backend& x) -> int { return (eval_is_zero(x) ? 0 : 1); } template constexpr auto eval_convert_to ( UnsignedIntegralType* result, const uintwide_t_backend& val, std::enable_if_t<( std::is_integral::value && (!std::is_signed ::value))>* p_nullparam = nullptr ) -> void { static_cast(p_nullparam); using local_unsigned_integral_type = UnsignedIntegralType; static_assert((!std::is_signed::value), "Error: Wrong signed instantiation (destination type should be unsigned)."); *result = static_cast(val.crepresentation()); } template constexpr auto eval_convert_to ( SignedIntegralType* result, const uintwide_t_backend& val, std::enable_if_t<( (std::is_integral::value) && (std::is_signed ::value))>* p_nullparam = nullptr ) -> void { static_cast(p_nullparam); using local_signed_integral_type = SignedIntegralType; static_assert(std::is_signed::value, "Error: Wrong unsigned instantiation (destination type should be signed)."); *result = static_cast(val.crepresentation()); } template< #if defined(WIDE_INTEGER_NAMESPACE) const WIDE_INTEGER_NAMESPACE::math::wide_integer::size_t MyWidth2, #else const ::math::wide_integer::size_t MyWidth2, #endif typename MyLimbType, typename MyAllocatorType> constexpr auto eval_convert_to(long double* result, const uintwide_t_backend& val) -> void { *result = static_cast(val.crepresentation()); } template< #if defined(WIDE_INTEGER_NAMESPACE) const WIDE_INTEGER_NAMESPACE::math::wide_integer::size_t MyWidth2, #else const ::math::wide_integer::size_t MyWidth2, #endif typename MyLimbType, typename MyAllocatorType> constexpr auto hash_value(const uintwide_t_backend& val) -> std::size_t { return val.hash(); } #if(__cplusplus >= 201703L) } // namespace boost::multiprecision #else } // namespace multiprecision } // namespace boost #endif #if (BOOST_VERSION < 107900) #if(__cplusplus >= 201703L) namespace boost::math::policies { #else namespace boost { namespace math { namespace policies { // NOLINT(modernize-concat-nested-namespaces) #endif // Specialization of the precision structure. template< #if defined(WIDE_INTEGER_NAMESPACE) const WIDE_INTEGER_NAMESPACE::math::wide_integer::size_t MyWidth2, #else const ::math::wide_integer::size_t MyWidth2, #endif typename MyLimbType, typename MyAllocatorType, typename ThisPolicy, const boost::multiprecision::expression_template_option ExpressionTemplatesOptions> struct precision, ExpressionTemplatesOptions>, ThisPolicy> { using precision_type = typename ThisPolicy::precision_type; using local_digits_2 = digits2; #if (BOOST_VERSION <= 107500) using type = typename mpl::if_c <((local_digits_2::value <= precision_type::value) || (precision_type::value <= 0)), local_digits_2, precision_type>::type; #else using type = typename std::conditional<((local_digits_2::value <= precision_type::value) || (precision_type::value <= 0)), local_digits_2, precision_type>::type; #endif }; #if(__cplusplus >= 201703L) } // namespace boost::math::policies #else } // namespace policies } // namespace math } // namespace boost #endif #endif namespace std // NOLINT(cert-dcl58-cpp) { template< #if defined(WIDE_INTEGER_NAMESPACE) const WIDE_INTEGER_NAMESPACE::math::wide_integer::size_t MyWidth2, #else const ::math::wide_integer::size_t MyWidth2, #endif typename MyLimbType, typename MyAllocatorType, const boost::multiprecision::expression_template_option ExpressionTemplatesOptions> class numeric_limits, ExpressionTemplatesOptions>> { public: static constexpr bool is_specialized = true; static constexpr bool is_signed = false; static constexpr bool is_integer = true; static constexpr bool is_exact = true; static constexpr bool is_bounded = true; static constexpr bool is_modulo = false; static constexpr bool is_iec559 = false; static constexpr int digits = MyWidth2; static constexpr int digits10 = static_cast((MyWidth2 * 301LL) / 1000LL); static constexpr int max_digits10 = static_cast((MyWidth2 * 301LL) / 1000LL); #if defined(WIDE_INTEGER_NAMESPACE) static constexpr int max_exponent = std::numeric_limits>::max_exponent; static constexpr int max_exponent10 = std::numeric_limits>::max_exponent10; static constexpr int min_exponent = std::numeric_limits>::min_exponent; static constexpr int min_exponent10 = std::numeric_limits>::min_exponent10; #else static constexpr int max_exponent = std::numeric_limits<::math::wide_integer::uintwide_t>::max_exponent; static constexpr int max_exponent10 = std::numeric_limits<::math::wide_integer::uintwide_t>::max_exponent10; static constexpr int min_exponent = std::numeric_limits<::math::wide_integer::uintwide_t>::min_exponent; static constexpr int min_exponent10 = std::numeric_limits<::math::wide_integer::uintwide_t>::min_exponent10; #endif static constexpr int radix = 2; static constexpr std::float_round_style round_style = std::round_to_nearest; static constexpr bool has_infinity = false; static constexpr bool has_quiet_NaN = false; static constexpr bool has_signaling_NaN = false; #ifdef _MSC_VER # pragma warning(push) # pragma warning(disable : 4996) #elif (defined(__clang__) && (__clang_major__ >= 17)) # pragma clang diagnostic push # pragma clang diagnostic ignored "-Wdeprecated-declarations" #endif static constexpr std::float_denorm_style has_denorm = std::denorm_absent; #ifdef _MSC_VER #pragma warning(pop) #elif (defined(__clang__) && (__clang_major__ >= 17)) # pragma clang diagnostic pop #endif static constexpr bool has_denorm_loss = false; static constexpr bool traps = false; static constexpr bool tinyness_before = false; #if defined(WIDE_INTEGER_NAMESPACE) static constexpr auto (min) () -> boost::multiprecision::number, ExpressionTemplatesOptions> { return boost::multiprecision::uintwide_t_backend((std::numeric_limits>::min)() ); } static constexpr auto (max) () -> boost::multiprecision::number, ExpressionTemplatesOptions> { return boost::multiprecision::uintwide_t_backend((std::numeric_limits>::max)() ); } static constexpr auto lowest () -> boost::multiprecision::number, ExpressionTemplatesOptions> { return boost::multiprecision::uintwide_t_backend (std::numeric_limits>::lowest ); } static constexpr auto epsilon () -> boost::multiprecision::number, ExpressionTemplatesOptions> { return boost::multiprecision::uintwide_t_backend (std::numeric_limits>::epsilon ); } static constexpr auto round_error () -> boost::multiprecision::number, ExpressionTemplatesOptions> { return boost::multiprecision::uintwide_t_backend (std::numeric_limits>::round_error ); } static constexpr auto infinity () -> boost::multiprecision::number, ExpressionTemplatesOptions> { return boost::multiprecision::uintwide_t_backend (std::numeric_limits>::infinity ); } static constexpr auto quiet_NaN () -> boost::multiprecision::number, ExpressionTemplatesOptions> { return boost::multiprecision::uintwide_t_backend (std::numeric_limits>::quiet_NaN ); } // NOLINT(readability-identifier-naming) static constexpr auto signaling_NaN() -> boost::multiprecision::number, ExpressionTemplatesOptions> { return boost::multiprecision::uintwide_t_backend (std::numeric_limits>::signaling_NaN); } // NOLINT(readability-identifier-naming) static constexpr auto denorm_min () -> boost::multiprecision::number, ExpressionTemplatesOptions> { return boost::multiprecision::uintwide_t_backend (std::numeric_limits>::denorm_min ); } #else static constexpr auto (min) () -> boost::multiprecision::number, ExpressionTemplatesOptions> { return boost::multiprecision::uintwide_t_backend((std::numeric_limits<::math::wide_integer::uintwide_t>::min)() ); } static constexpr auto (max) () -> boost::multiprecision::number, ExpressionTemplatesOptions> { return boost::multiprecision::uintwide_t_backend((std::numeric_limits<::math::wide_integer::uintwide_t>::max)() ); } static constexpr auto lowest () -> boost::multiprecision::number, ExpressionTemplatesOptions> { return boost::multiprecision::uintwide_t_backend (std::numeric_limits<::math::wide_integer::uintwide_t>::lowest ); } static constexpr auto epsilon () -> boost::multiprecision::number, ExpressionTemplatesOptions> { return boost::multiprecision::uintwide_t_backend (std::numeric_limits<::math::wide_integer::uintwide_t>::epsilon ); } static constexpr auto round_error () -> boost::multiprecision::number, ExpressionTemplatesOptions> { return boost::multiprecision::uintwide_t_backend (std::numeric_limits<::math::wide_integer::uintwide_t>::round_error ); } static constexpr auto infinity () -> boost::multiprecision::number, ExpressionTemplatesOptions> { return boost::multiprecision::uintwide_t_backend (std::numeric_limits<::math::wide_integer::uintwide_t>::infinity ); } static constexpr auto quiet_NaN () -> boost::multiprecision::number, ExpressionTemplatesOptions> { return boost::multiprecision::uintwide_t_backend (std::numeric_limits<::math::wide_integer::uintwide_t>::quiet_NaN ); } // NOLINT(readability-identifier-naming) static constexpr auto signaling_NaN() -> boost::multiprecision::number, ExpressionTemplatesOptions> { return boost::multiprecision::uintwide_t_backend (std::numeric_limits<::math::wide_integer::uintwide_t>::signaling_NaN); } // NOLINT(readability-identifier-naming) static constexpr auto denorm_min () -> boost::multiprecision::number, ExpressionTemplatesOptions> { return boost::multiprecision::uintwide_t_backend (std::numeric_limits<::math::wide_integer::uintwide_t>::denorm_min ); } #endif }; #ifndef BOOST_NO_INCLASS_MEMBER_INITIALIZATION #if defined(WIDE_INTEGER_NAMESPACE) template constexpr bool std::numeric_limits, ExpressionTemplatesOptions>>::is_specialized; // NOLINT(readability-redundant-declaration) template constexpr bool std::numeric_limits, ExpressionTemplatesOptions>>::is_signed; // NOLINT(readability-redundant-declaration) template constexpr bool std::numeric_limits, ExpressionTemplatesOptions>>::is_integer; // NOLINT(readability-redundant-declaration) template constexpr bool std::numeric_limits, ExpressionTemplatesOptions>>::is_exact; // NOLINT(readability-redundant-declaration) template constexpr bool std::numeric_limits, ExpressionTemplatesOptions>>::is_bounded; // NOLINT(readability-redundant-declaration) template constexpr bool std::numeric_limits, ExpressionTemplatesOptions>>::is_modulo; // NOLINT(readability-redundant-declaration) template constexpr bool std::numeric_limits, ExpressionTemplatesOptions>>::is_iec559; // NOLINT(readability-redundant-declaration) template constexpr int std::numeric_limits, ExpressionTemplatesOptions>>::digits; // NOLINT(readability-redundant-declaration) template constexpr int std::numeric_limits, ExpressionTemplatesOptions>>::digits10; // NOLINT(readability-redundant-declaration) template constexpr int std::numeric_limits, ExpressionTemplatesOptions>>::max_digits10; // NOLINT(readability-redundant-declaration) template constexpr int std::numeric_limits, ExpressionTemplatesOptions>>::max_exponent; // NOLINT(readability-redundant-declaration) template constexpr int std::numeric_limits, ExpressionTemplatesOptions>>::max_exponent10; // NOLINT(readability-redundant-declaration) template constexpr int std::numeric_limits, ExpressionTemplatesOptions>>::min_exponent; // NOLINT(readability-redundant-declaration) template constexpr int std::numeric_limits, ExpressionTemplatesOptions>>::min_exponent10; // NOLINT(readability-redundant-declaration) template constexpr int std::numeric_limits, ExpressionTemplatesOptions>>::radix; // NOLINT(readability-redundant-declaration) template constexpr std::float_round_style std::numeric_limits, ExpressionTemplatesOptions>>::round_style; // NOLINT(readability-redundant-declaration) template constexpr bool std::numeric_limits, ExpressionTemplatesOptions>>::has_infinity; // NOLINT(readability-redundant-declaration) template constexpr bool std::numeric_limits, ExpressionTemplatesOptions>>::has_quiet_NaN; // NOLINT(readability-redundant-declaration) template constexpr bool std::numeric_limits, ExpressionTemplatesOptions>>::has_signaling_NaN; // NOLINT(readability-redundant-declaration) #ifdef _MSC_VER # pragma warning(push) # pragma warning(disable : 4996) #elif (defined(__clang__) && (__clang_major__ >= 17)) # pragma clang diagnostic push # pragma clang diagnostic ignored "-Wdeprecated-declarations" #endif template constexpr std::float_denorm_style std::numeric_limits, ExpressionTemplatesOptions>>::has_denorm; // NOLINT(readability-redundant-declaration) #ifdef _MSC_VER #pragma warning(pop) #elif (defined(__clang__) && (__clang_major__ >= 17)) # pragma clang diagnostic pop #endif template constexpr bool std::numeric_limits, ExpressionTemplatesOptions>>::has_denorm_loss; // NOLINT(readability-redundant-declaration) template constexpr bool std::numeric_limits, ExpressionTemplatesOptions>>::traps; // NOLINT(readability-redundant-declaration) template constexpr bool std::numeric_limits, ExpressionTemplatesOptions>>::tinyness_before; // NOLINT(readability-redundant-declaration) #else template constexpr bool std::numeric_limits, ExpressionTemplatesOptions>>::is_specialized; // NOLINT(readability-redundant-declaration) template constexpr bool std::numeric_limits, ExpressionTemplatesOptions>>::is_signed; // NOLINT(readability-redundant-declaration) template constexpr bool std::numeric_limits, ExpressionTemplatesOptions>>::is_integer; // NOLINT(readability-redundant-declaration) template constexpr bool std::numeric_limits, ExpressionTemplatesOptions>>::is_exact; // NOLINT(readability-redundant-declaration) template constexpr bool std::numeric_limits, ExpressionTemplatesOptions>>::is_bounded; // NOLINT(readability-redundant-declaration) template constexpr bool std::numeric_limits, ExpressionTemplatesOptions>>::is_modulo; // NOLINT(readability-redundant-declaration) template constexpr bool std::numeric_limits, ExpressionTemplatesOptions>>::is_iec559; // NOLINT(readability-redundant-declaration) template constexpr int std::numeric_limits, ExpressionTemplatesOptions>>::digits; // NOLINT(readability-redundant-declaration) template constexpr int std::numeric_limits, ExpressionTemplatesOptions>>::digits10; // NOLINT(readability-redundant-declaration) template constexpr int std::numeric_limits, ExpressionTemplatesOptions>>::max_digits10; // NOLINT(readability-redundant-declaration) template constexpr int std::numeric_limits, ExpressionTemplatesOptions>>::max_exponent; // NOLINT(readability-redundant-declaration) template constexpr int std::numeric_limits, ExpressionTemplatesOptions>>::max_exponent10; // NOLINT(readability-redundant-declaration) template constexpr int std::numeric_limits, ExpressionTemplatesOptions>>::min_exponent; // NOLINT(readability-redundant-declaration) template constexpr int std::numeric_limits, ExpressionTemplatesOptions>>::min_exponent10; // NOLINT(readability-redundant-declaration) template constexpr int std::numeric_limits, ExpressionTemplatesOptions>>::radix; // NOLINT(readability-redundant-declaration) template constexpr std::float_round_style std::numeric_limits, ExpressionTemplatesOptions>>::round_style; // NOLINT(readability-redundant-declaration) template constexpr bool std::numeric_limits, ExpressionTemplatesOptions>>::has_infinity; // NOLINT(readability-redundant-declaration) template constexpr bool std::numeric_limits, ExpressionTemplatesOptions>>::has_quiet_NaN; // NOLINT(readability-redundant-declaration) template constexpr bool std::numeric_limits, ExpressionTemplatesOptions>>::has_signaling_NaN; // NOLINT(readability-redundant-declaration) #ifdef _MSC_VER # pragma warning(push) # pragma warning(disable : 4996) #elif (defined(__clang__) && (__clang_major__ >= 17)) # pragma clang diagnostic push # pragma clang diagnostic ignored "-Wdeprecated-declarations" #endif template constexpr std::float_denorm_style std::numeric_limits, ExpressionTemplatesOptions>>::has_denorm; // NOLINT(readability-redundant-declaration) #ifdef _MSC_VER #pragma warning(pop) #elif (defined(__clang__) && (__clang_major__ >= 17)) # pragma clang diagnostic pop #endif template constexpr bool std::numeric_limits, ExpressionTemplatesOptions>>::has_denorm_loss; // NOLINT(readability-redundant-declaration) template constexpr bool std::numeric_limits, ExpressionTemplatesOptions>>::traps; // NOLINT(readability-redundant-declaration) template constexpr bool std::numeric_limits, ExpressionTemplatesOptions>>::tinyness_before; // NOLINT(readability-redundant-declaration) #endif #endif // !BOOST_NO_INCLASS_MEMBER_INITIALIZATION } // namespace std #if (BOOST_VERSION < 108000) #if ((defined(__clang__) && (__clang_major__ > 9)) && !defined(__APPLE__)) #pragma GCC diagnostic pop #endif #endif #if (defined(__GNUC__) && !defined(__clang__) && (__GNUC__ >= 12)) #pragma GCC diagnostic pop #endif #if (BOOST_VERSION < 108000) #if defined(__GNUC__) #pragma GCC diagnostic pop #pragma GCC diagnostic pop #pragma GCC diagnostic pop #endif #endif #endif // UINTWIDE_T_BACKEND_2019_12_15_HPP ================================================ FILE: codecov.yml ================================================ # ------------------------------------------------------------------------------ # Copyright Christopher Kormanyos 2020 - 2026. # Distributed under the Boost Software License, # Version 1.0. (See accompanying file LICENSE_1_0.txt # or copy at http://www.boost.org/LICENSE_1_0.txt) # ------------------------------------------------------------------------------ codecov: require_ci_to_pass: yes coverage: precision: 1 round: up range: '50...100' status: project: default: # This can be anything, but it needs to exist as the name # basic settings target: 90% threshold: 3% if_ci_failed: error #success, failure, error, ignore only_pulls: false patch: default: target: 75% threshold: 25% parsers: gcov: branch_detection: conditional: no loop: no method: no macro: no comment: layout: 'reach,diff,flags,files,footer' behavior: default require_changes: no ================================================ FILE: examples/CMakeLists.txt ================================================ add_library(Examples example000_numeric_limits.cpp example000a_builtin_convert.cpp example001_mul_div.cpp example001a_div_mod.cpp example002_shl_shr.cpp example003_sqrt.cpp example003a_cbrt.cpp example004_rootk_pow.cpp example005_powm.cpp example005a_pow_factors_of_p99.cpp example006_gcd.cpp example007_random_generator.cpp example008_miller_rabin_prime.cpp example008a_miller_rabin_prime.cpp example008b_solovay_strassen_prime.cpp example009_timed_mul.cpp example009a_timed_mul_4_by_4.cpp example009b_timed_mul_8_by_8.cpp example010_uint48_t.cpp example011_uint24_t.cpp example012_rsa_crypto.cpp example013_ecdsa_sign_verify.cpp example014_pi_spigot_wide.cpp) target_compile_features(Examples PRIVATE cxx_std_20) target_include_directories(Examples PRIVATE ${PROJECT_SOURCE_DIR}) target_include_directories(Examples SYSTEM PUBLIC ${Boost_INCLUDE_DIRS}) ================================================ FILE: examples/build/test_examples.sh ================================================ #!/bin/bash # Copyright Christopher Kormanyos 2020 - 2024. # Distributed under the Boost Software License, # Version 1.0. (See accompanying file LICENSE_1_0.txt # or copy at http://www.boost.org/LICENSE_1_0.txt) # if [[ "$1" != "" ]]; then GCC="$1" else GCC=g++ fi if [[ "$2" != "" ]]; then STD="$2" else STD=c++11 fi mkdir -p bin rm -f ./bin/*.* echo run examples with GCC="$GCC" STD="$STD" "$GCC" -std="$STD" -Wall -Werror -O3 -march=native -I../.. -DWIDE_INTEGER_STANDALONE_EXAMPLE000A_BUILTIN_CONVERT ../../examples/example000a_builtin_convert.cpp -o ./bin/example000a_builtin_convert.exe ls -la ./bin/example000a_builtin_convert.exe "$GCC" -std="$STD" -Wall -Werror -O3 -march=native -I../.. -DWIDE_INTEGER_STANDALONE_EXAMPLE000_NUMERIC_LIMITS ../../examples/example000_numeric_limits.cpp -o ./bin/example000_numeric_limits.exe ls -la ./bin/example000_numeric_limits.exe "$GCC" -std="$STD" -Wall -Werror -O3 -march=native -I../.. -DWIDE_INTEGER_STANDALONE_EXAMPLE001A_DIV_MOD ../../examples/example001a_div_mod.cpp -o ./bin/example001a_div_mod.exe ls -la ./bin/example001a_div_mod.exe "$GCC" -std="$STD" -Wall -Werror -O3 -march=native -I../.. -DWIDE_INTEGER_STANDALONE_EXAMPLE001_MUL_DIV ../../examples/example001_mul_div.cpp -o ./bin/example001_mul_div.exe ls -la ./bin/example001_mul_div.exe "$GCC" -std="$STD" -Wall -Werror -O3 -march=native -I../.. -DWIDE_INTEGER_STANDALONE_EXAMPLE002_SHL_SHR ../../examples/example002_shl_shr.cpp -o ./bin/example002_shl_shr.exe ls -la ./bin/example002_shl_shr.exe "$GCC" -std="$STD" -Wall -Werror -O3 -march=native -I../.. -DWIDE_INTEGER_STANDALONE_EXAMPLE003A_CBRT ../../examples/example003a_cbrt.cpp -o ./bin/example003a_cbrt.exe ls -la ./bin/example003a_cbrt.exe "$GCC" -std="$STD" -Wall -Werror -O3 -march=native -I../.. -DWIDE_INTEGER_STANDALONE_EXAMPLE003_SQRT ../../examples/example003_sqrt.cpp -o ./bin/example003_sqrt.exe ls -la ./bin/example003_sqrt.exe "$GCC" -std="$STD" -Wall -Werror -O3 -march=native -I../.. -DWIDE_INTEGER_STANDALONE_EXAMPLE004_ROOTK_POW ../../examples/example004_rootk_pow.cpp -o ./bin/example004_rootk_pow.exe ls -la ./bin/example004_rootk_pow.exe "$GCC" -std="$STD" -Wall -Werror -O3 -march=native -I../.. -DWIDE_INTEGER_STANDALONE_EXAMPLE005A_POW_FACTORS_OF_P99 ../../examples/example005a_pow_factors_of_p99.cpp -o ./bin/example005a_pow_factors_of_p99.exe ls -la ./bin/example005a_pow_factors_of_p99.exe "$GCC" -std="$STD" -Wall -Werror -O3 -march=native -I../.. -DWIDE_INTEGER_STANDALONE_EXAMPLE005_POWM ../../examples/example005_powm.cpp -o ./bin/example005_powm.exe ls -la ./bin/example005_powm.exe "$GCC" -std="$STD" -Wall -Werror -O3 -march=native -I../.. -DWIDE_INTEGER_STANDALONE_EXAMPLE006_GCD ../../examples/example006_gcd.cpp -o ./bin/example006_gcd.exe ls -la ./bin/example006_gcd.exe "$GCC" -std="$STD" -Wall -Werror -O3 -march=native -I../.. -DWIDE_INTEGER_STANDALONE_EXAMPLE007_RANDOM_GENERATOR ../../examples/example007_random_generator.cpp -o ./bin/example007_random_generator.exe ls -la ./bin/example007_random_generator.exe "$GCC" -std="$STD" -Wall -Werror -O3 -march=native -I../.. -DWIDE_INTEGER_STANDALONE_EXAMPLE008_MILLER_RABIN_PRIME ../../examples/example008_miller_rabin_prime.cpp -o ./bin/example008_miller_rabin_prime.exe ls -la ./bin/example008_miller_rabin_prime.exe "$GCC" -std="$STD" -Wall -Werror -O3 -march=native -I../.. -DWIDE_INTEGER_STANDALONE_EXAMPLE009A_TIMED_MUL_4_BY_4 ../../examples/example009a_timed_mul_4_by_4.cpp -o ./bin/example009a_timed_mul_4_by_4.exe ls -la ./bin/example009a_timed_mul_4_by_4.exe "$GCC" -std="$STD" -Wall -Werror -O3 -march=native -I../.. -DWIDE_INTEGER_STANDALONE_EXAMPLE009B_TIMED_MUL_8_BY_8 ../../examples/example009b_timed_mul_8_by_8.cpp -o ./bin/example009b_timed_mul_8_by_8.exe ls -la ./bin/example009b_timed_mul_8_by_8.exe "$GCC" -std="$STD" -Wall -Werror -O3 -march=native -I../.. -DWIDE_INTEGER_STANDALONE_EXAMPLE009_TIMED_MUL ../../examples/example009_timed_mul.cpp -o ./bin/example009_timed_mul.exe ls -la ./bin/example009_timed_mul.exe "$GCC" -std="$STD" -Wall -Werror -O3 -march=native -I../.. -DWIDE_INTEGER_STANDALONE_EXAMPLE010_UINT48_T ../../examples/example010_uint48_t.cpp -o ./bin/example010_uint48_t.exe ls -la ./bin/example010_uint48_t.exe "$GCC" -std="$STD" -Wall -Werror -O3 -march=native -I../.. -DWIDE_INTEGER_STANDALONE_EXAMPLE011_UINT24_T ../../examples/example011_uint24_t.cpp -o ./bin/example011_uint24_t.exe ls -la ./bin/example011_uint24_t.exe "$GCC" -std="$STD" -Wall -Werror -O3 -march=native -I../.. -DWIDE_INTEGER_STANDALONE_EXAMPLE012_RSA_CRYPTO ../../examples/example012_rsa_crypto.cpp -o ./bin/example012_rsa_crypto.exe ls -la ./bin/example012_rsa_crypto.exe "$GCC" -std="$STD" -Wall -Werror -O3 -march=native -I../.. -DWIDE_INTEGER_STANDALONE_EXAMPLE013_ECDSA_SIGN_VERIFY ../../examples/example013_ecdsa_sign_verify.cpp -o ./bin/example013_ecdsa_sign_verify.exe ls -la ./bin/example013_ecdsa_sign_verify.exe ./bin/example000a_builtin_convert.exe result_var_000a_builtin_convert=$? ./bin/example000_numeric_limits.exe result_var_000_numeric_limits=$? ./bin/example001a_div_mod.exe result_var_001a_div_mod=$? ./bin/example001_mul_div.exe result_var_001_mul_div=$? ./bin/example002_shl_shr.exe result_var_002_shl_shr=$? ./bin/example003a_cbrt.exe result_var_003a_cbrt=$? ./bin/example003_sqrt.exe result_var_003_sqrt=$? ./bin/example004_rootk_pow.exe result_var_004_rootk_pow=$? ./bin/example005a_pow_factors_of_p99.exe result_var_005a_pow_factors_of_p99=$? ./bin/example005_powm.exe result_var_005_powm=$? ./bin/example006_gcd.exe result_var_006_gcd=$? ./bin/example007_random_generator.exe result_var_007_random_generator=$? ./bin/example008_miller_rabin_prime.exe result_var_008_miller_rabin_prime=$? ./bin/example009a_timed_mul_4_by_4.exe result_var_009a_timed_mul_4_by_4=$? ./bin/example009b_timed_mul_8_by_8.exe result_var_009b_timed_mul_8_by_8=$? ./bin/example009_timed_mul.exe result_var_009_timed_mul=$? ./bin/example010_uint48_t.exe result_var_010_uint48_t=$? ./bin/example011_uint24_t.exe result_var_011_uint24_t=$? ./bin/example012_rsa_crypto.exe result_var_012_rsa_crypto=$? ./bin/example013_ecdsa_sign_verify.exe result_var_013_ecdsa_sign_verify=$? echo "result_var_000a_builtin_convert : " "$result_var_000a_builtin_convert" echo "result_var_000_numeric_limits : " "$result_var_000_numeric_limits" echo "result_var_001a_div_mod : " "$result_var_001a_div_mod" echo "result_var_001_mul_div : " "$result_var_001_mul_div" echo "result_var_002_shl_shr : " "$result_var_002_shl_shr" echo "result_var_003a_cbrt : " "$result_var_003a_cbrt" echo "result_var_003_sqrt : " "$result_var_003_sqrt" echo "result_var_004_rootk_pow : " "$result_var_004_rootk_pow" echo "result_var_005a_pow_factors_of_p99 : " "$result_var_005a_pow_factors_of_p99" echo "result_var_005_powm : " "$result_var_005_powm" echo "result_var_006_gcd : " "$result_var_006_gcd" echo "result_var_007_random_generator : " "$result_var_007_random_generator" echo "result_var_008_miller_rabin_prime : " "$result_var_008_miller_rabin_prime" echo "result_var_009a_timed_mul_4_by_4 : " "$result_var_009a_timed_mul_4_by_4" echo "result_var_009b_timed_mul_8_by_8 : " "$result_var_009b_timed_mul_8_by_8" echo "result_var_009_timed_mul : " "$result_var_009_timed_mul" echo "result_var_010_uint48_t : " "$result_var_010_uint48_t" echo "result_var_011_uint24_t : " "$result_var_011_uint24_t" echo "result_var_012_rsa_crypto : " "$result_var_012_rsa_crypto" echo "result_var_013_ecdsa_sign_verify : " "$result_var_013_ecdsa_sign_verify" result_total=$((result_var_000a_builtin_convert+result_var_000_numeric_limits+result_var_001a_div_mod+result_var_001_mul_div+result_var_002_shl_shr+result_var_003a_cbrt+result_var_003_sqrt+result_var_004_rootk_pow+result_var_005a_pow_factors_of_p99+result_var_005_powm+result_var_006_gcd+result_var_007_random_generator+result_var_008_miller_rabin_prime+result_var_009a_timed_mul_4_by_4+result_var_009b_timed_mul_8_by_8+result_var_009_timed_mul+result_var_010_uint48_t+result_var_011_uint24_t+result_var_012_rsa_crypto+result_var_013_ecdsa_sign_verify)) echo "result_total : " "$result_total" exit $result_total ================================================ FILE: examples/example000_numeric_limits.cpp ================================================ /////////////////////////////////////////////////////////////////// // Copyright Christopher Kormanyos 2021 - 2025. // // Distributed under the Boost Software License, // // Version 1.0. (See accompanying file LICENSE_1_0.txt // // or copy at http://www.boost.org/LICENSE_1_0.txt) // /////////////////////////////////////////////////////////////////// #include #include namespace local { #if defined(WIDE_INTEGER_NAMESPACE) using WIDE_INTEGER_NAMESPACE::math::wide_integer::uint64_t; using WIDE_INTEGER_NAMESPACE::math::wide_integer::int64_t; #else using ::math::wide_integer::uint64_t; using ::math::wide_integer::int64_t; #endif #if defined(WIDE_INTEGER_NAMESPACE) using uint32_t = WIDE_INTEGER_NAMESPACE::math::wide_integer::uintwide_t(UINT32_C(32)), std::uint8_t, void, false>; using int32_t = WIDE_INTEGER_NAMESPACE::math::wide_integer::uintwide_t(UINT32_C(32)), std::uint8_t, void, true>; #else using uint32_t = ::math::wide_integer::uintwide_t(UINT32_C(32)), std::uint8_t, void, false>; using int32_t = ::math::wide_integer::uintwide_t(UINT32_C(32)), std::uint8_t, void, true>; #endif } // namespace local #if defined(WIDE_INTEGER_NAMESPACE) auto WIDE_INTEGER_NAMESPACE::math::wide_integer::example000_numeric_limits() -> bool #else auto ::math::wide_integer::example000_numeric_limits() -> bool #endif { bool result_is_ok = true; { #if defined(WIDE_INTEGER_NAMESPACE) using WIDE_INTEGER_NAMESPACE::math::wide_integer::uint256_t; #else using ::math::wide_integer::uint256_t; #endif constexpr uint256_t my_max("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"); constexpr uint256_t my_min(0U); constexpr bool result_uint256_t_is_ok = ((std::numeric_limits::max) () == my_max) && ((std::numeric_limits::min) () == my_min) && ( std::numeric_limits::lowest() == uint256_t(std::numeric_limits::lowest())) && ( std::numeric_limits::digits == static_cast(INT32_C(256))) && ( std::numeric_limits::digits10 == static_cast(INT32_C(77))) ; static_assert(result_uint256_t_is_ok, "Error: example000_numeric_limits unsigned not OK!"); result_is_ok = (result_uint256_t_is_ok && result_is_ok); } { #if defined(WIDE_INTEGER_NAMESPACE) using WIDE_INTEGER_NAMESPACE::math::wide_integer::int256_t; #else using ::math::wide_integer::int256_t; #endif constexpr int256_t my_max ("0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"); constexpr int256_t my_min ("0x8000000000000000000000000000000000000000000000000000000000000000"); #if (defined(_MSC_VER) && (_MSC_VER < 1920)) #pragma warning(push) #pragma warning(disable : 4307) #endif constexpr int256_t my_min2 ("-57896044618658097711785492504343953926634992332820282019728792003956564819968"); #if (defined(_MSC_VER) && (_MSC_VER < 1920)) #pragma warning(pop) #endif constexpr int256_t my_lowest = my_min2; static_assert((std::numeric_limits::max) () == my_max, "Error: example000_numeric_limits signed not OK!"); static_assert((std::numeric_limits::min) () == my_min, "Error: example000_numeric_limits signed not OK!"); static_assert((std::numeric_limits::min) () == my_min2, "Error: example000_numeric_limits signed not OK!"); static_assert( std::numeric_limits::lowest() == my_lowest, "Error: example000_numeric_limits signed not OK!"); static_assert( std::numeric_limits::digits == static_cast(INT32_C(255)), "Error: example000_numeric_limits signed not OK!"); static_assert( std::numeric_limits::digits10 == static_cast(INT32_C(76)), "Error: example000_numeric_limits signed not OK!"); constexpr bool result_int256_t_is_ok = ((std::numeric_limits::max) () == my_max) && ((std::numeric_limits::min) () == my_min) && ((std::numeric_limits::min) () == my_min2) && ( std::numeric_limits::lowest() == my_lowest) && ( std::numeric_limits::digits == static_cast(INT32_C(255))) && ( std::numeric_limits::digits10 == static_cast(INT32_C(76))) ; static_assert(result_int256_t_is_ok, "Error: example000_numeric_limits signed not OK!"); result_is_ok = (result_int256_t_is_ok && result_is_ok); } { constexpr bool result_uint64_t_is_ok = ((std::numeric_limits::max) () == (std::numeric_limits::max) ()) && ((std::numeric_limits::min) () == (std::numeric_limits::min) ()) && ( std::numeric_limits::lowest() == std::numeric_limits::lowest()) && ( std::numeric_limits::lowest() == -1 - (std::numeric_limits::max)()) && ( std::numeric_limits::digits == std::numeric_limits::digits ) && ( std::numeric_limits::digits10 == std::numeric_limits::digits10) ; static_assert(result_uint64_t_is_ok, "Error: example000_numeric_limits unsigned not OK!"); result_is_ok = (result_uint64_t_is_ok && result_is_ok); } { constexpr bool result_int64_t_is_ok = ((std::numeric_limits::max) () == (std::numeric_limits::max) ()) && ((std::numeric_limits::min) () == (std::numeric_limits::min) ()) && ( std::numeric_limits::lowest() == std::numeric_limits::lowest()) && ( std::numeric_limits::lowest() == -1 - (std::numeric_limits::max)()) && ( std::numeric_limits::digits == std::numeric_limits::digits ) && ( std::numeric_limits::digits10 == std::numeric_limits::digits10) ; static_assert(result_int64_t_is_ok, "Error: example000_numeric_limits unsigned not OK!"); result_is_ok = (result_int64_t_is_ok && result_is_ok); } { constexpr bool result_uint32_t_is_ok = ((std::numeric_limits::max) () == (std::numeric_limits::max) ()) && ((std::numeric_limits::min) () == (std::numeric_limits::min) ()) && ( std::numeric_limits::lowest() == std::numeric_limits::lowest()) && ( std::numeric_limits::lowest() == -1 - (std::numeric_limits::max)()) && ( std::numeric_limits::digits == std::numeric_limits::digits ) && ( std::numeric_limits::digits10 == std::numeric_limits::digits10) ; static_assert(result_uint32_t_is_ok, "Error: example000_numeric_limits unsigned not OK!"); result_is_ok = (result_uint32_t_is_ok && result_is_ok); } { constexpr bool result_int32_t_is_ok = ((std::numeric_limits::max) () == (std::numeric_limits::max) ()) && ((std::numeric_limits::min) () == (std::numeric_limits::min) ()) && ( std::numeric_limits::lowest() == std::numeric_limits::lowest()) && ( std::numeric_limits::lowest() == -1 - (std::numeric_limits::max)()) && ( std::numeric_limits::digits == std::numeric_limits::digits ) && ( std::numeric_limits::digits10 == std::numeric_limits::digits10) ; static_assert(result_int32_t_is_ok, "Error: example000_numeric_limits unsigned not OK!"); result_is_ok = (result_int32_t_is_ok && result_is_ok); } return result_is_ok; } // Enable this if you would like to activate this main() as a standalone example. #if defined(WIDE_INTEGER_STANDALONE_EXAMPLE000_NUMERIC_LIMITS) #include #include auto main() -> int { #if defined(WIDE_INTEGER_NAMESPACE) const auto result_is_ok = WIDE_INTEGER_NAMESPACE::math::wide_integer::example000_numeric_limits(); #else const auto result_is_ok = ::math::wide_integer::example000_numeric_limits(); #endif std::cout << "result_is_ok: " << std::boolalpha << result_is_ok << std::endl; return (result_is_ok ? 0 : -1); } #endif ================================================ FILE: examples/example000a_builtin_convert.cpp ================================================ /////////////////////////////////////////////////////////////////// // Copyright Christopher Kormanyos 2021 - 2025. // // Distributed under the Boost Software License, // // Version 1.0. (See accompanying file LICENSE_1_0.txt // // or copy at http://www.boost.org/LICENSE_1_0.txt) // /////////////////////////////////////////////////////////////////// #include #include namespace local { template constexpr auto fabs(NumericType a) -> NumericType { return ((a < static_cast(INT8_C(0))) ? -a : a); // LCOV_EXCL_LINE } } // namespace local #if defined(WIDE_INTEGER_NAMESPACE) auto WIDE_INTEGER_NAMESPACE::math::wide_integer::example000a_builtin_convert() -> bool #else auto ::math::wide_integer::example000a_builtin_convert() -> bool #endif { auto result_is_ok = true; #if defined(WIDE_INTEGER_NAMESPACE) using WIDE_INTEGER_NAMESPACE::math::wide_integer::int256_t; #else using ::math::wide_integer::int256_t; #endif { constexpr int256_t n = -1234567.89; // NOLINT(cppcoreguidelines-avoid-magic-numbers,readability-magic-numbers) constexpr auto result_n_is_ok = (n == -1234567); // NOLINT(cppcoreguidelines-avoid-magic-numbers,readability-magic-numbers) static_assert(result_n_is_ok, "Error: example000a_builtin_convert not OK!"); result_is_ok = (result_n_is_ok && result_is_ok); } { constexpr int256_t n = "-12345678900000000000000000000000"; constexpr auto f = static_cast(n); constexpr auto closeness = local::fabs(1.0F - local::fabs(f / -1.23456789E31F)); // NOLINT(cppcoreguidelines-avoid-magic-numbers,readability-magic-numbers) constexpr auto result_f_is_ok = (closeness < std::numeric_limits::epsilon()); static_assert(result_f_is_ok, "Error: example000a_builtin_convert not OK!"); result_is_ok = (result_f_is_ok && result_is_ok); } { constexpr int256_t n = "-123456789000000000"; constexpr auto n64 = static_cast(n); constexpr auto result_n_is_ok = (n64 == INT64_C(-123456789000000000)); static_assert((n64 == INT64_C(-123456789000000000)), "Error: example000a_builtin_convert not OK!"); result_is_ok = (result_n_is_ok && result_is_ok); } return result_is_ok; } // Enable this if you would like to activate this main() as a standalone example. #if defined(WIDE_INTEGER_STANDALONE_EXAMPLE000A_BUILTIN_CONVERT) #include #include auto main() -> int { #if defined(WIDE_INTEGER_NAMESPACE) const auto result_is_ok = WIDE_INTEGER_NAMESPACE::math::wide_integer::example000a_builtin_convert(); #else const auto result_is_ok = ::math::wide_integer::example000a_builtin_convert(); #endif std::cout << "result_is_ok: " << std::boolalpha << result_is_ok << std::endl; return (result_is_ok ? 0 : -1); } #endif ================================================ FILE: examples/example001_mul_div.cpp ================================================ /////////////////////////////////////////////////////////////////// // Copyright Christopher Kormanyos 2018 - 2025. // // Distributed under the Boost Software License, // // Version 1.0. (See accompanying file LICENSE_1_0.txt // // or copy at http://www.boost.org/LICENSE_1_0.txt) // /////////////////////////////////////////////////////////////////// #include #include #if defined(WIDE_INTEGER_NAMESPACE) auto WIDE_INTEGER_NAMESPACE::math::wide_integer::example001_mul_div() -> bool #else auto ::math::wide_integer::example001_mul_div() -> bool #endif { #if defined(WIDE_INTEGER_NAMESPACE) using WIDE_INTEGER_NAMESPACE::math::wide_integer::uint256_t; using WIDE_INTEGER_NAMESPACE::math::wide_integer::uint512_t; #else using ::math::wide_integer::uint256_t; using ::math::wide_integer::uint512_t; #endif static_assert(( std::numeric_limits::digits == static_cast(INT16_C(256)) && std::numeric_limits::digits == static_cast(INT16_C(512))), "Error: Incorrect digit count for this example"); constexpr uint256_t a("0xF4DF741DE58BCB2F37F18372026EF9CBCFC456CB80AF54D53BDEED78410065DE"); constexpr uint256_t b("0x166D63E0202B3D90ECCEAA046341AB504658F55B974A7FD63733ECF89DD0DF75"); constexpr auto c = uint512_t(a) * uint512_t(b); constexpr auto d = (a / b); constexpr auto result_is_ok = ( (c == "0x1573D6A7CEA734D99865C4F428184983CDB018B80E9CC44B83C773FBE11993E7E491A360C57EB4306C61F9A04F7F7D99BE3676AAD2D71C5592D5AE70F84AF076") && (static_cast(d) == static_cast(UINT8_C(10))) ); static_assert(result_is_ok, "Error: example001_mul_div not OK!"); return result_is_ok; } // Enable this if you would like to activate this main() as a standalone example. #if defined(WIDE_INTEGER_STANDALONE_EXAMPLE001_MUL_DIV) #if !defined(WIDE_INTEGER_DISABLE_IOSTREAM) #include #include #endif constexpr auto example_standalone_foodcafe = static_cast(UINT32_C(0xF00DCAFE)); extern "C" { extern volatile std::uint32_t example_standalone_result; auto example_run_standalone () -> bool; auto example_get_standalone_result() noexcept -> bool; auto example_run_standalone() -> bool { bool result_is_ok = true; for(unsigned i = 0U; i < 64U; ++i) { #if defined(WIDE_INTEGER_NAMESPACE) result_is_ok &= WIDE_INTEGER_NAMESPACE::math::wide_integer::example001_mul_div(); #else result_is_ok &= ::math::wide_integer::example001_mul_div(); #endif } example_standalone_result = static_cast ( result_is_ok ? example_standalone_foodcafe : static_cast(UINT32_C(0xFFFFFFFF)) ); #if !defined(WIDE_INTEGER_DISABLE_IOSTREAM) std::cout << "result_is_ok: " << std::boolalpha << result_is_ok << std::endl; #endif return result_is_ok; } auto example_get_standalone_result() noexcept -> bool { return { example_standalone_result == static_cast(UINT32_C(0xF00DCAFE)) }; } } auto main() -> int { auto result_is_ok = true; result_is_ok = (::example_run_standalone () && result_is_ok); result_is_ok = (::example_get_standalone_result() && result_is_ok); return (result_is_ok ? 0 : -1); } extern "C" { volatile std::uint32_t example_standalone_result { }; } #endif ================================================ FILE: examples/example001a_div_mod.cpp ================================================ /////////////////////////////////////////////////////////////////// // Copyright Christopher Kormanyos 2018 -2025. // // Distributed under the Boost Software License, // // Version 1.0. (See accompanying file LICENSE_1_0.txt // // or copy at http://www.boost.org/LICENSE_1_0.txt) // /////////////////////////////////////////////////////////////////// #include #include #if defined(WIDE_INTEGER_NAMESPACE) auto WIDE_INTEGER_NAMESPACE::math::wide_integer::example001a_div_mod() -> bool #else auto ::math::wide_integer::example001a_div_mod() -> bool #endif { #if defined(WIDE_INTEGER_NAMESPACE) using WIDE_INTEGER_NAMESPACE::math::wide_integer::uint512_t; #else using ::math::wide_integer::uint512_t; #endif // Consider: QuotientRemainder[698937339790347543053797400564366118744312537138445607919548628175822115805812983955794321304304417541511379093392776018867245622409026835324102460829431,100041341335406267530943777943625254875702684549707174207105689918734693139781] // Expected control result: {6986485091668619828842978360442127600954041171641881730123945989288792389271,100041341335406267530943777943625254875702684549707174207105689918734693139780} constexpr uint512_t a("698937339790347543053797400564366118744312537138445607919548628175822115805812983955794321304304417541511379093392776018867245622409026835324102460829431"); constexpr uint512_t b("100041341335406267530943777943625254875702684549707174207105689918734693139781"); constexpr uint512_t c = (a / b); constexpr uint512_t d = (a % b); constexpr bool result_is_ok = ( (c == "6986485091668619828842978360442127600954041171641881730123945989288792389271") && (d == "100041341335406267530943777943625254875702684549707174207105689918734693139780")); static_assert(result_is_ok, "Error: example001a_div_mod not OK!"); return result_is_ok; } // Enable this if you would like to activate this main() as a standalone example. #if defined(WIDE_INTEGER_STANDALONE_EXAMPLE001A_DIV_MOD) #include #include auto main() -> int { #if defined(WIDE_INTEGER_NAMESPACE) const auto result_is_ok = WIDE_INTEGER_NAMESPACE::math::wide_integer::example001a_div_mod(); #else const auto result_is_ok = ::math::wide_integer::example001a_div_mod(); #endif std::cout << "result_is_ok: " << std::boolalpha << result_is_ok << std::endl; return (result_is_ok ? 0 : -1); } #endif ================================================ FILE: examples/example002_shl_shr.cpp ================================================ /////////////////////////////////////////////////////////////////// // Copyright Christopher Kormanyos 2018 - 2025. // // Distributed under the Boost Software License, // // Version 1.0. (See accompanying file LICENSE_1_0.txt // // or copy at http://www.boost.org/LICENSE_1_0.txt) // /////////////////////////////////////////////////////////////////// #include #include #if defined(WIDE_INTEGER_NAMESPACE) auto WIDE_INTEGER_NAMESPACE::math::wide_integer::example002_shl_shr() -> bool #else auto ::math::wide_integer::example002_shl_shr() -> bool #endif { #if defined(WIDE_INTEGER_NAMESPACE) using WIDE_INTEGER_NAMESPACE::math::wide_integer::uint256_t; #else using ::math::wide_integer::uint256_t; #endif constexpr uint256_t a("0xF4DF741DE58BCB2F37F18372026EF9CBCFC456CB80AF54D53BDEED78410065DE"); constexpr uint256_t c = (a << 67); // NOLINT(cppcoreguidelines-avoid-magic-numbers,readability-magic-numbers) constexpr uint256_t d = (a >> 79); // NOLINT(cppcoreguidelines-avoid-magic-numbers,readability-magic-numbers) const auto result_is_ok = ( (c == "0xBF8C1B901377CE5E7E22B65C057AA6A9DEF76BC208032EF00000000000000000") && (d == "0x1E9BEE83BCB17965E6FE306E404DDF3979F88AD97015E")); static_assert(result_is_ok, "Error: example002_shl_shr not OK!"); return result_is_ok; } // Enable this if you would like to activate this main() as a standalone example. #if defined(WIDE_INTEGER_STANDALONE_EXAMPLE002_SHL_SHR) #include #include auto main() -> int { #if defined(WIDE_INTEGER_NAMESPACE) const auto result_is_ok = WIDE_INTEGER_NAMESPACE::math::wide_integer::example002_shl_shr(); #else const auto result_is_ok = ::math::wide_integer::example002_shl_shr(); #endif std::cout << "result_is_ok: " << std::boolalpha << result_is_ok << std::endl; return (result_is_ok ? 0 : -1); } #endif ================================================ FILE: examples/example003_sqrt.cpp ================================================ /////////////////////////////////////////////////////////////////// // Copyright Christopher Kormanyos 2018 - 2025. // // Distributed under the Boost Software License, // // Version 1.0. (See accompanying file LICENSE_1_0.txt // // or copy at http://www.boost.org/LICENSE_1_0.txt) // /////////////////////////////////////////////////////////////////// #include #include #if defined(WIDE_INTEGER_NAMESPACE) auto WIDE_INTEGER_NAMESPACE::math::wide_integer::example003_sqrt() -> bool #else auto ::math::wide_integer::example003_sqrt() -> bool #endif { #if defined(WIDE_INTEGER_NAMESPACE) using WIDE_INTEGER_NAMESPACE::math::wide_integer::uint256_t; #else using ::math::wide_integer::uint256_t; #endif constexpr uint256_t a("0xF4DF741DE58BCB2F37F18372026EF9CBCFC456CB80AF54D53BDEED78410065DE"); constexpr uint256_t s = sqrt(a); constexpr bool result_is_ok = (s == "0xFA5FE7853F1D4AD92BDF244179CA178B"); static_assert(result_is_ok, "Error: example003_sqrt not OK!"); return result_is_ok; } // Enable this if you would like to activate this main() as a standalone example. #if defined(WIDE_INTEGER_STANDALONE_EXAMPLE003_SQRT) #if !defined(WIDE_INTEGER_DISABLE_IOSTREAM) #include #include #endif constexpr auto example_standalone_foodcafe = static_cast(UINT32_C(0xF00DCAFE)); extern "C" { extern volatile std::uint32_t example_standalone_result; auto example_run_standalone () -> bool; auto example_get_standalone_result() noexcept -> bool; auto example_run_standalone() -> bool { bool result_is_ok = true; for(unsigned i = 0U; i < 64U; ++i) { #if defined(WIDE_INTEGER_NAMESPACE) result_is_ok &= WIDE_INTEGER_NAMESPACE::math::wide_integer::example003_sqrt(); #else result_is_ok &= ::math::wide_integer::example003_sqrt(); #endif } example_standalone_result = static_cast ( result_is_ok ? example_standalone_foodcafe : static_cast(UINT32_C(0xFFFFFFFF)) ); #if !defined(WIDE_INTEGER_DISABLE_IOSTREAM) std::cout << "result_is_ok: " << std::boolalpha << result_is_ok << std::endl; #endif return result_is_ok; } auto example_get_standalone_result() noexcept -> bool { return { example_standalone_result == static_cast(UINT32_C(0xF00DCAFE)) }; } } auto main() -> int { auto result_is_ok = true; result_is_ok = (::example_run_standalone () && result_is_ok); result_is_ok = (::example_get_standalone_result() && result_is_ok); return (result_is_ok ? 0 : -1); } extern "C" { volatile std::uint32_t example_standalone_result { }; } #endif ================================================ FILE: examples/example003a_cbrt.cpp ================================================ /////////////////////////////////////////////////////////////////// // Copyright Christopher Kormanyos 2018 - 2025. // // Distributed under the Boost Software License, // // Version 1.0. (See accompanying file LICENSE_1_0.txt // // or copy at http://www.boost.org/LICENSE_1_0.txt) // /////////////////////////////////////////////////////////////////// #include #include #include #if defined(WIDE_INTEGER_NAMESPACE) auto WIDE_INTEGER_NAMESPACE::math::wide_integer::example003a_cbrt() -> bool #else auto ::math::wide_integer::example003a_cbrt() -> bool #endif { #if defined(WIDE_INTEGER_NAMESPACE) using uint11264_t = WIDE_INTEGER_NAMESPACE::math::wide_integer::uintwide_t(UINT32_C(11264)), std::uint32_t, std::allocator>; #else using uint11264_t = ::math::wide_integer::uintwide_t(UINT32_C(11264)), std::uint32_t, std::allocator>; #endif // Create the string '1' + 3,333 times '0', which is // equivalent to the decimal integral value 10^3333. const std::string str_a = "1" + std::string(3333U, '0'); const uint11264_t a = str_a.data(); const uint11264_t s = cbrt(a); // Create the string '1' + 1,111 times '0', which is // equivalent to the decimal integral value 10^1111. // (This is the cube root of 10^3333.) const std::string str_control = "1" + std::string(1111U, '0'); const auto result_is_ok = (s == uint11264_t(str_control.data())); return result_is_ok; } // Enable this if you would like to activate this main() as a standalone example. #if defined(WIDE_INTEGER_STANDALONE_EXAMPLE003A_CBRT) #include #include auto main() -> int { #if defined(WIDE_INTEGER_NAMESPACE) const auto result_is_ok = WIDE_INTEGER_NAMESPACE::math::wide_integer::example003a_cbrt(); #else const auto result_is_ok = ::math::wide_integer::example003a_cbrt(); #endif std::cout << "result_is_ok: " << std::boolalpha << result_is_ok << std::endl; return (result_is_ok ? 0 : -1); } #endif ================================================ FILE: examples/example004_rootk_pow.cpp ================================================ /////////////////////////////////////////////////////////////////// // Copyright Christopher Kormanyos 2018 - 2025. // // Distributed under the Boost Software License, // // Version 1.0. (See accompanying file LICENSE_1_0.txt // // or copy at http://www.boost.org/LICENSE_1_0.txt) // /////////////////////////////////////////////////////////////////// #include #include #if defined(WIDE_INTEGER_NAMESPACE) auto WIDE_INTEGER_NAMESPACE::math::wide_integer::example004_rootk_pow() -> bool #else auto ::math::wide_integer::example004_rootk_pow() -> bool #endif { bool result_is_ok = true; { #if defined(WIDE_INTEGER_NAMESPACE) using WIDE_INTEGER_NAMESPACE::math::wide_integer::uint256_t; #else using ::math::wide_integer::uint256_t; #endif constexpr uint256_t x("0x95E0E51079E1D11737D3FD01429AA745582FEB4381D61FA56948C1A949E43C32"); constexpr uint256_t r = rootk(x, 7U); // NOLINT(cppcoreguidelines-avoid-magic-numbers,readability-magic-numbers) constexpr bool result_is_ok_root = (r == UINT64_C(0x16067D1894)); result_is_ok = (result_is_ok_root && result_is_ok); static_assert(result_is_ok_root, "Error: example004_rootk_pow not OK!"); } { #if defined(WIDE_INTEGER_NAMESPACE) using WIDE_INTEGER_NAMESPACE::math::wide_integer::uint256_t; #else using ::math::wide_integer::uint256_t; #endif constexpr uint256_t r { static_cast(UINT64_C(0x16067D1894)) }; constexpr uint256_t p = pow(r, static_cast(UINT8_C(7))); constexpr bool result_is_ok_pow = (p == "0x95E0E5104B2F636571834936C982E40EFA25682E7370CD1C248051E1CDC34000"); result_is_ok = (result_is_ok_pow && result_is_ok); static_assert(result_is_ok_pow, "Error: example004_rootk_pow not OK!"); } { #if defined(WIDE_INTEGER_NAMESPACE) using WIDE_INTEGER_NAMESPACE::math::wide_integer::int256_t; #else using ::math::wide_integer::int256_t; #endif constexpr int256_t x("-17791969125525294590007745776736486317864490689865550963808715359713140948018"); constexpr int256_t r = cbrt(x); constexpr bool result_is_ok_root = (r == int256_t("-26106060416733621800766427")); result_is_ok = (result_is_ok_root && result_is_ok); static_assert(result_is_ok_root, "Error: example004_rootk_pow not OK!"); } { #if defined(WIDE_INTEGER_NAMESPACE) using WIDE_INTEGER_NAMESPACE::math::wide_integer::int256_t; #else using ::math::wide_integer::int256_t; #endif constexpr int256_t x("-17791969125525294590007745776736486317864490689865550963808715359713140948018"); constexpr int256_t r = rootk(x, 3); constexpr bool result_is_ok_root = (r == int256_t("-26106060416733621800766427")); result_is_ok = (result_is_ok_root && result_is_ok); static_assert(result_is_ok_root, "Error: example004_rootk_pow not OK!"); } return result_is_ok; } // Enable this if you would like to activate this main() as a standalone example. #if defined(WIDE_INTEGER_STANDALONE_EXAMPLE004_ROOTK_POW) #include #include auto main() -> int { #if defined(WIDE_INTEGER_NAMESPACE) const auto result_is_ok = WIDE_INTEGER_NAMESPACE::math::wide_integer::example004_rootk_pow(); #else const auto result_is_ok = ::math::wide_integer::example004_rootk_pow(); #endif std::cout << "result_is_ok: " << std::boolalpha << result_is_ok << std::endl; return (result_is_ok ? 0 : -1); } #endif ================================================ FILE: examples/example005_powm.cpp ================================================ /////////////////////////////////////////////////////////////////// // Copyright Christopher Kormanyos 2018 - 2025. // // Distributed under the Boost Software License, // // Version 1.0. (See accompanying file LICENSE_1_0.txt // // or copy at http://www.boost.org/LICENSE_1_0.txt) // /////////////////////////////////////////////////////////////////// #include #include #if defined(WIDE_INTEGER_NAMESPACE) auto WIDE_INTEGER_NAMESPACE::math::wide_integer::example005_powm() -> bool #else auto ::math::wide_integer::example005_powm() -> bool #endif { #if defined(WIDE_INTEGER_NAMESPACE) using WIDE_INTEGER_NAMESPACE::math::wide_integer::uint256_t; #else using ::math::wide_integer::uint256_t; #endif constexpr uint256_t b("0xDA4033C9B1B0675C20B7879EA63FFFBEEBEC3F89F78D22C393FAD98E7AE9BF69"); constexpr uint256_t p("0xA4748AD2DAFEED29C73927BD0945EF45EFEC9DAA95CC59390D406FC27236A174"); constexpr uint256_t m("0xB6EC4DAB21E2856D488D669C210DC1FAD00366F92D602B1D42B88E24531F907E"); const uint256_t c = powm(b, p, m); const auto result_is_ok = (c == "0x5231F0EF6BBB3E78B9D7B1FA5F86EFA932E71BABD8A1CFF2C9EE5C396284ED07"); return result_is_ok; } // Enable this if you would like to activate this main() as a standalone example. #if defined(WIDE_INTEGER_STANDALONE_EXAMPLE005_POWM) #include #include auto main() -> int { #if defined(WIDE_INTEGER_NAMESPACE) const auto result_is_ok = WIDE_INTEGER_NAMESPACE::math::wide_integer::example005_powm(); #else const auto result_is_ok = ::math::wide_integer::example005_powm(); #endif std::cout << "result_is_ok: " << std::boolalpha << result_is_ok << std::endl; return (result_is_ok ? 0 : -1); } #endif ================================================ FILE: examples/example005a_pow_factors_of_p99.cpp ================================================ /////////////////////////////////////////////////////////////////// // Copyright Christopher Kormanyos 2018 - 2025. // // Distributed under the Boost Software License, // // Version 1.0. (See accompanying file LICENSE_1_0.txt // // or copy at http://www.boost.org/LICENSE_1_0.txt) // /////////////////////////////////////////////////////////////////// #include #include #if defined(WIDE_INTEGER_NAMESPACE) auto WIDE_INTEGER_NAMESPACE::math::wide_integer::example005a_pow_factors_of_p99() -> bool #else auto ::math::wide_integer::example005a_pow_factors_of_p99() -> bool #endif { #if defined(WIDE_INTEGER_NAMESPACE) using uint384_t = WIDE_INTEGER_NAMESPACE::math::wide_integer::uintwide_t(UINT32_C(384))>; #else using uint384_t = ::math::wide_integer::uintwide_t(UINT32_C(384))>; #endif const uint384_t c = (pow(uint384_t(10U), 99) - 1) / 9; // Consider Table 9, page 410 of the classic work: // H. Riesel, "Prime Numbers and Computer Methods of Factorization", // Second Edition (Birkhaeuser, 1994). In that table, we find the // prime factorization of P99 = (10^99 - 1) / 9. This example // verifies the tabulated result. // FactorInteger[(10^33 - 1)/9] const uint384_t control_p33 { uint384_t(3U) * uint384_t(37U) * uint384_t(67U) * uint384_t(21649U) * uint384_t(513239U) * uint384_t("1344628210313298373") }; // FactorInteger[(10^99 - 1)/9] const uint384_t control_p99 { control_p33 * uint384_t(3U) * uint384_t(199U) * uint384_t(397U) * uint384_t(34849U) * uint384_t(333667U) * uint384_t("362853724342990469324766235474268869786311886053883") }; const auto result_is_ok = (c == control_p99); return result_is_ok; } // Enable this if you would like to activate this main() as a standalone example. #if defined(WIDE_INTEGER_STANDALONE_EXAMPLE005A_POW_FACTORS_OF_P99) #include #include auto main() -> int { #if defined(WIDE_INTEGER_NAMESPACE) const auto result_is_ok = WIDE_INTEGER_NAMESPACE::math::wide_integer::example005a_pow_factors_of_p99(); #else const auto result_is_ok = ::math::wide_integer::example005a_pow_factors_of_p99(); #endif std::cout << "result_is_ok: " << std::boolalpha << result_is_ok << std::endl; return (result_is_ok ? 0 : -1); } #endif ================================================ FILE: examples/example006_gcd.cpp ================================================ /////////////////////////////////////////////////////////////////// // Copyright Christopher Kormanyos 2018 - 2025. // // Distributed under the Boost Software License, // // Version 1.0. (See accompanying file LICENSE_1_0.txt // // or copy at http://www.boost.org/LICENSE_1_0.txt) // /////////////////////////////////////////////////////////////////// #include #include #if defined(WIDE_INTEGER_NAMESPACE) auto WIDE_INTEGER_NAMESPACE::math::wide_integer::example006_gcd() -> bool #else auto ::math::wide_integer::example006_gcd() -> bool #endif { #if defined(WIDE_INTEGER_NAMESPACE) using WIDE_INTEGER_NAMESPACE::math::wide_integer::uint256_t; #else using ::math::wide_integer::uint256_t; #endif auto result_is_ok = true; { constexpr auto a = uint256_t("0x1035452A5197CF882B5B5EB64C8CCFEE4D772F9F7B66A239649A43093464EFF5"); constexpr auto b = uint256_t("0xB4F6151D727361113083D9A0DEB91B0B62A250F65DA6543823703D0140C873AD"); constexpr auto c = gcd(a, b); constexpr auto result_gcd_is_ok = (static_cast(c) == static_cast(UINT32_C(11759761))); static_assert(result_gcd_is_ok, "Error: example006_gcd not OK!"); result_is_ok = (result_gcd_is_ok && result_is_ok); } { constexpr auto a = uint256_t("0xD2690CD26CD57A3C443993851A70D3B62F841573668DF7B229508371A0AEDE7F"); constexpr auto b = uint256_t("0xFE719235CD0B1A314D4CA6940AEDC38BDF8E9484E68CE814EDAA17D87B0B4CC8"); constexpr auto c = gcd(a, b); constexpr auto result_gcd_is_ok = (static_cast(c) == static_cast(UINT32_C(12170749))); static_assert(result_gcd_is_ok, "Error: example006_gcd not OK!"); result_is_ok = (result_gcd_is_ok && result_is_ok); } { constexpr auto a = uint256_t("0x7495AFF66DCB1085DC4CC294ECCBB1B455F65765DD4E9735564FDD80A05168A"); constexpr auto b = uint256_t("0x7A0543EF0705942D09962172ED5038814AE6EDF8EED2FC6C52CF317D253BC81F"); constexpr auto c = gcd(a, b); constexpr auto result_gcd_is_ok = (static_cast(c) == static_cast(UINT32_C(13520497))); static_assert(result_gcd_is_ok, "Error: example006_gcd not OK!"); result_is_ok = (result_gcd_is_ok && result_is_ok); } return result_is_ok; } // Enable this if you would like to activate this main() as a standalone example. #if defined(WIDE_INTEGER_STANDALONE_EXAMPLE006_GCD) #include #include auto main() -> int { #if defined(WIDE_INTEGER_NAMESPACE) const auto result_is_ok = WIDE_INTEGER_NAMESPACE::math::wide_integer::example006_gcd(); #else const auto result_is_ok = ::math::wide_integer::example006_gcd(); #endif std::cout << "result_is_ok: " << std::boolalpha << result_is_ok << std::endl; return (result_is_ok ? 0 : -1); } #endif ================================================ FILE: examples/example007_random_generator.cpp ================================================ /////////////////////////////////////////////////////////////////// // Copyright Christopher Kormanyos 2018 - 2025. // // Distributed under the Boost Software License, // // Version 1.0. (See accompanying file LICENSE_1_0.txt // // or copy at http://www.boost.org/LICENSE_1_0.txt) // /////////////////////////////////////////////////////////////////// #include #include #include #include #include namespace local_random { template auto generate() -> bool { using random_engine_type = std::mersenne_twister_engine(UINT32_C( 64)), static_cast(UINT32_C(312)), static_cast(UINT32_C(156)), static_cast(UINT32_C( 31)), UINT64_C(0xB5026F5AA96619E9), static_cast(UINT32_C( 29)), UINT64_C(0x5555555555555555), static_cast(UINT32_C( 17)), UINT64_C(0x71D67FFFEDA60000), static_cast(UINT32_C( 37)), UINT64_C(0xFFF7EEE000000000), static_cast(UINT32_C( 43)), UINT64_C(6364136223846793005)>; #if defined(WIDE_INTEGER_NAMESPACE) using wide_integer_type = WIDE_INTEGER_NAMESPACE::math::wide_integer::uintwide_t(UINT32_C(256)), std::uint32_t, AllocatorType>; using distribution_type = WIDE_INTEGER_NAMESPACE::math::wide_integer::uniform_int_distribution; #else using wide_integer_type = ::math::wide_integer::uintwide_t(UINT32_C(256)), std::uint32_t, AllocatorType>; using distribution_type = ::math::wide_integer::uniform_int_distribution; #endif // Generate a random number with wide_integer_type having limbs of type LimbType. // Purosely use the default seed. random_engine_type generator; // NOLINT(cert-msc32-c,cert-msc51-cpp) distribution_type distribution { }; const wide_integer_type n = distribution(generator); const auto result_is_ok = (n == wide_integer_type("0xF258D22D4DB91392B5EE8CB6ABE457F8401F7AC78BC80F1CC96D191CF6F6AEA6")); return result_is_ok; } } // namespace local_random #if defined(WIDE_INTEGER_NAMESPACE) auto WIDE_INTEGER_NAMESPACE::math::wide_integer::example007_random_generator() -> bool #else auto ::math::wide_integer::example007_random_generator() -> bool #endif { const bool result_08_is_ok = local_random::generate (); const bool result_16_is_ok = local_random::generate(); const bool result_32_is_ok = local_random::generate(); const auto result_is_ok = ( result_08_is_ok && result_16_is_ok && result_32_is_ok); return result_is_ok; } // Enable this if you would like to activate this main() as a standalone example. #if defined(WIDE_INTEGER_STANDALONE_EXAMPLE007_RANDOM_GENERATOR) #include #include auto main() -> int { #if defined(WIDE_INTEGER_NAMESPACE) const auto result_is_ok = WIDE_INTEGER_NAMESPACE::math::wide_integer::example007_random_generator(); #else const auto result_is_ok = ::math::wide_integer::example007_random_generator(); #endif std::cout << "result_is_ok: " << std::boolalpha << result_is_ok << std::endl; return (result_is_ok ? 0 : -1); } #endif ================================================ FILE: examples/example008_miller_rabin_prime.cpp ================================================ /////////////////////////////////////////////////////////////////// // Copyright Christopher Kormanyos 2018 - 2026. // // Distributed under the Boost Software License, // // Version 1.0. (See accompanying file LICENSE_1_0.txt // // or copy at http://www.boost.org/LICENSE_1_0.txt) // /////////////////////////////////////////////////////////////////// // This Miller-Rabin primality test is loosely based on // an adaptation of some code from Boost.Multiprecision. // The Boost.Multiprecision code can be found here: // https://www.boost.org/doc/libs/1_90_0/libs/multiprecision/doc/html/boost_multiprecision/tut/primetest.html #include #include #include #include #if defined(__clang__) #if defined __has_feature && __has_feature(thread_sanitizer) #define UINTWIDE_T_REDUCE_TEST_DEPTH #endif #elif defined(__GNUC__) #if defined(__SANITIZE_THREAD__) || defined(WIDE_INTEGER_HAS_COVERAGE) #define UINTWIDE_T_REDUCE_TEST_DEPTH #endif #elif defined(_MSC_VER) #if defined(_DEBUG) #define UINTWIDE_T_REDUCE_TEST_DEPTH #endif #endif namespace local_example008_miller_rabin_prime { #if defined(WIDE_INTEGER_NAMESPACE) using wide_integer_type = WIDE_INTEGER_NAMESPACE::math::wide_integer::uintwide_t(UINT32_C(512))>; using distribution_type = WIDE_INTEGER_NAMESPACE::math::wide_integer::uniform_int_distribution; #else using wide_integer_type = ::math::wide_integer::uintwide_t(UINT32_C(512))>; using distribution_type = ::math::wide_integer::uniform_int_distribution; #endif using random_engine1_type = std::linear_congruential_engine; using random_engine2_type = std::mt19937; auto example008_miller_rabin_prime_run() -> bool; auto example008_miller_rabin_prime_run() -> bool { // Use a pseudo-random seed for this test. random_engine1_type generator1(util::util_pseudorandom_time_point_seed::value()); random_engine2_type generator2(util::util_pseudorandom_time_point_seed::value()); distribution_type distribution1; wide_integer_type p0; wide_integer_type p1; for(;;) { p0 = distribution1(generator1); distribution_type distribution2 { wide_integer_type { 2U }, p0 - 1U }; const bool miller_rabin_result = miller_rabin(p0, 25U, distribution2, generator2); if(miller_rabin_result) { break; } } for(;;) { p1 = distribution1(generator1); distribution_type distribution2 { wide_integer_type { 2U }, p0 - 1U }; const bool miller_rabin_result = miller_rabin(p1, 25U, distribution2, generator2); if(miller_rabin_result) { break; } } const auto gd = gcd(p0, p1); const auto result_is_ok = ( (p0 != static_cast(UINT8_C(0))) && (p1 != static_cast(UINT8_C(0))) && (p0 != p1) && (gd == static_cast(UINT8_C(1)))); return result_is_ok; } auto example008_miller_rabin_prime_check_known_primes() -> bool; auto example008_miller_rabin_prime_check_known_primes() -> bool { #if !defined(UINTWIDE_T_REDUCE_TEST_DEPTH) constexpr auto primes_array_count = static_cast(UINT8_C(28)); #else constexpr auto primes_array_count = static_cast(UINT8_C(4)); #endif using known_primes_array_type = std::array; const auto known_primes = known_primes_array_type { wide_integer_type("1350668399695862095705378871871078275422204299410029680022807229578447177486838048356600483814274341298941322922278646278082691661579262242972653147843881"), wide_integer_type("6316533715112802448288092604478054524383926634811945757057640178392735989589363869889681632218704486270766492727631128625563552112105808239098327091824521"), wide_integer_type("4858586217250992689079636758246308353014067931891277522662097117263017348927716654355835947116278934662184099633799310227887262043463022049904058963602113"), wide_integer_type("6019419207947545798517327619748393618031791796951797411174747320842950599875485354843571998416270218797959087329922954007679373990444302239974053043273173"), #if !defined(UINTWIDE_T_REDUCE_TEST_DEPTH) wide_integer_type("2623115045263242825415413671896042727657332322988674224271913776550889477454553016178535650310812678634291673863620916079255756983038819930429300055323617"), wide_integer_type("3003848015480415325081996052076028272879191508991266945638241025854760400469061295504211346716924852976586414875652009123799821021749062743721323009536589"), wide_integer_type("5568337324913975213045841890066332347573591111951280366169746765603974031759890673193278087261510160253710813073898966574448941498158599660295718450413969"), wide_integer_type("3899092769157768302620084735536775086413273751852623051586317377248088862913234601759046503051512549835620467902724675884204543889535019159859544426497689"), wide_integer_type("4880233062753644655310200777146080067274805955812121495803730551248986874932581198974746359764046223936780348192151675074968829396304926645738459150294633"), wide_integer_type("2981493811876081198746361294505357003171188931549722884629126574527379655453586512421136559407326464729329418005336291630284117366942572742648076658621793"), wide_integer_type("2311447178623403864122136445969808248907814278870229050269813814615527678820577823271523594807805953636283537824863549493053563901315483672394027660220781"), wide_integer_type("3479071810465946698893564410603359501484777617936440665021184921238051587645202575681993903459105745702439079512468629916692256642323236436208584510861069"), wide_integer_type("6118926406334289174567277866138349610455081780960756500741587206842789898877382284319927664574788247571122480984323699664304605053422838920108157647074869"), wide_integer_type("5590335646861485447121090043941130683713858202654698267088158519958402198517001330817356690577780346497360906009275424722046395721643723271668335885539113"), wide_integer_type("4600898139597524599763199946635257244387697856987579864564123646981189843032360401339979289535161473255665149405050376631425564431369445938758414793076901"), wide_integer_type("4315306784386454402272613378470925299536719882405387670534486076073677209483117906338062419164521262724975133161632270609178741350949903249729845258787733"), wide_integer_type("5950481506592244740042852475032761031143767332677168744969800384139374680573074295152251652710948027287864530732080292167390630350615454944427411014041141"), wide_integer_type("2440980104093377665340267319609708156057114020162041419246265162721394309112466086681318371709997847741488133816937847915825174882442455843460458950869789"), wide_integer_type("4365212508738551992055010318700772806707699100481394233862331936291205769739000493695684304355128758915801551136191115096132710582148081523015262320554393"), wide_integer_type("3781985616534097915844902700666149069763815834328308181456271045363812894911075580338484224113219563989181987256586477816830560104618708627118533065620341"), wide_integer_type("6312111327629281870461906157964428032414795872246359612186802568161839869980963702584858942079006607549034530874234327750267701726691921864700120963919449"), wide_integer_type("3457298715359430348699008011012486630342527178370025440230151409769901896560575367519479882530184023906479055022991404575620008255488477625490456126386873"), wide_integer_type("6382461542071546162407085982360686365702447907013055208214815317050235935992759617609828663308694238400452867139555655406217610647086518464256672670959569"), wide_integer_type("6068775473164015507047528585305834886132568156674171703370121517708258623288855684363295365245992564330637765075823775316688120061787431995297819368086373"), wide_integer_type("6070463708262743334734874588409415398342276766482324769914482379758057124149747442871974246654319915559096090055433661153568555118115638391055646124587309"), wide_integer_type("6297032304320012154880388332146509431687962719889593388307760834122241251586999352542604072606959905346551948057937113980815914420810768937615250771878461"), wide_integer_type("6128722501467469312821769346772700466471416838690252468887811095595451174847178063191879577266340073924505285489011360630545669076007556359186484284685741"), wide_integer_type("5334118887555315545538097460404232946047447099403008196978701351362864400468260258361331949883359663365575253347639015242447351434717477630139194429944273") #endif }; random_engine1_type generator(util::util_pseudorandom_time_point_seed::value()); distribution_type distribution; auto result_is_ok = true; for(const auto& p : known_primes) { const auto result_known_prime_is_ok = miller_rabin(p, 25U, distribution, generator); result_is_ok = (result_known_prime_is_ok && result_is_ok); } return result_is_ok; } } // namespace local_example008_miller_rabin_prime #if defined(WIDE_INTEGER_NAMESPACE) auto WIDE_INTEGER_NAMESPACE::math::wide_integer::example008_miller_rabin_prime() -> bool #else auto ::math::wide_integer::example008_miller_rabin_prime() -> bool #endif { auto result_is_ok = true; for(auto i = static_cast(UINT8_C(0)); #if !defined(UINTWIDE_T_REDUCE_TEST_DEPTH) i < static_cast(UINT8_C(16)); #else i < static_cast(UINT8_C(4)); #endif ++i) { const auto result_prime_run_is_ok = local_example008_miller_rabin_prime::example008_miller_rabin_prime_run(); result_is_ok = (result_prime_run_is_ok && result_is_ok); } { const auto result_known_primes_is_ok = local_example008_miller_rabin_prime::example008_miller_rabin_prime_check_known_primes(); result_is_ok = (result_known_primes_is_ok && result_is_ok); } return result_is_ok; } // Enable this if you would like to activate this main() as a standalone example. #if defined(WIDE_INTEGER_STANDALONE_EXAMPLE008_MILLER_RABIN_PRIME) #include #include auto main() -> int { #if defined(WIDE_INTEGER_NAMESPACE) const auto result_is_ok = WIDE_INTEGER_NAMESPACE::math::wide_integer::example008_miller_rabin_prime(); #else const auto result_is_ok = ::math::wide_integer::example008_miller_rabin_prime(); #endif std::cout << "result_is_ok: " << std::boolalpha << result_is_ok << std::endl; return (result_is_ok ? 0 : -1); } #endif ================================================ FILE: examples/example008a_miller_rabin_prime.cpp ================================================ /////////////////////////////////////////////////////////////////// // Copyright Christopher Kormanyos 2018 - 2026. // // Distributed under the Boost Software License, // // Version 1.0. (See accompanying file LICENSE_1_0.txt // // or copy at http://www.boost.org/LICENSE_1_0.txt) // /////////////////////////////////////////////////////////////////// // This Miller-Rabin primality test is loosely based on // an adaptation of some code from Boost.Multiprecision. // The Boost.Multiprecision code can be found here: // https://www.boost.org/doc/libs/1_90_0/libs/multiprecision/doc/html/boost_multiprecision/tut/primetest.html #include #include #include #include #include #if !defined(BOOST_VERSION) #error BOOST_VERSION is not defined. Ensure that is properly included. #endif #if ((BOOST_VERSION >= 107900) && !defined(BOOST_MP_STANDALONE)) #define BOOST_MP_STANDALONE #endif #if ((BOOST_VERSION >= 108000) && !defined(BOOST_NO_EXCEPTIONS)) #define BOOST_NO_EXCEPTIONS #endif #if (BOOST_VERSION < 108000) #if defined(__GNUC__) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wconversion" #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wsign-conversion" #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wunused-parameter" #endif #endif #if (defined(__GNUC__) && !defined(__clang__) && (__GNUC__ >= 12)) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wrestrict" #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Warray-bounds" #endif #if (BOOST_VERSION < 108000) #if ((defined(__clang__) && (__clang_major__ > 9)) && !defined(__APPLE__)) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wdeprecated-copy" #endif #endif #include #include #include namespace local_miller_rabin { template auto lexical_cast(const UnsignedIntegralType& u) -> std::string; template auto lexical_cast(const UnsignedIntegralType& u) -> std::string { std::stringstream ss; ss << u; return ss.str(); } } // namespace local_miller_rabin #if defined(WIDE_INTEGER_NAMESPACE) auto WIDE_INTEGER_NAMESPACE::math::wide_integer::example008a_miller_rabin_prime() -> bool #else auto ::math::wide_integer::example008a_miller_rabin_prime() -> bool #endif { #if defined(WIDE_INTEGER_NAMESPACE) using boost_wide_integer_type = boost::multiprecision::number(UINT32_C(512))>, boost::multiprecision::et_off>; #else using boost_wide_integer_type = boost::multiprecision::number(UINT32_C(512))>, boost::multiprecision::et_off>; #endif // This example uses wide_integer's uniform_int_distribution to select // prime candidates. These prime candidates are subsequently converted // (via string-streaming) to Boost.Multiprecision integers. #if defined(WIDE_INTEGER_NAMESPACE) using local_wide_integer_type = WIDE_INTEGER_NAMESPACE::math::wide_integer::uintwide_t (std::numeric_limits::digits)>; using local_distribution_type = WIDE_INTEGER_NAMESPACE::math::wide_integer::uniform_int_distribution(std::numeric_limits::digits)>; #else using local_wide_integer_type = ::math::wide_integer::uintwide_t (std::numeric_limits::digits)>; using local_distribution_type = ::math::wide_integer::uniform_int_distribution(std::numeric_limits::digits)>; #endif using random_engine1_type = std::mt19937; using random_engine2_type = std::linear_congruential_engine; // NOLINT(cppcoreguidelines-avoid-magic-numbers,readability-magic-numbers) const auto seed_start = ::util::util_pseudorandom_time_point_seed::value(); random_engine1_type gen1(static_cast(seed_start)); random_engine2_type gen2(static_cast(seed_start)); // Select prime candidates from a range of 10^150 ... max(uint512_t)-1. constexpr local_wide_integer_type dist_min ( "1" "00000000000000000000000000000000000000000000000000" "00000000000000000000000000000000000000000000000000" "00000000000000000000000000000000000000000000000000" ); local_distribution_type dist { dist_min, (std::numeric_limits::max)() - 1 }; boost_wide_integer_type p0 { }; boost_wide_integer_type p1 { }; auto dist_func = [&dist, &gen1]() // NOLINT(modernize-use-trailing-return-type) { const auto n = dist(gen1); return boost_wide_integer_type(local_miller_rabin::lexical_cast(n)); }; for(;;) { p0 = dist_func(); const auto p0_is_probably_prime = boost::multiprecision::miller_rabin_test(p0, 25U, gen2); if(p0_is_probably_prime) { break; } } const auto seed_next = ::util::util_pseudorandom_time_point_seed::value(); gen1.seed(static_cast(seed_next)); for(;;) { p1 = dist_func(); const auto p1_is_probably_prime = boost::multiprecision::miller_rabin_test(p1, 25U, gen2); if(p1_is_probably_prime) { break; } } const boost_wide_integer_type gd = gcd(p0, p1); const auto result_is_ok = ( (p0 > boost_wide_integer_type(local_miller_rabin::lexical_cast(dist_min))) && (p1 > boost_wide_integer_type(local_miller_rabin::lexical_cast(dist_min))) && (p0 != 0U) && (p1 != 0U) && (p0 != p1) && (gd == 1U)); return result_is_ok; } // Enable this if you would like to activate this main() as a standalone example. #if defined(WIDE_INTEGER_STANDALONE_EXAMPLE008A_MILLER_RABIN_PRIME) #include #include auto main() -> int // NOLINT(bugprone-exception-escape) { #if defined(WIDE_INTEGER_NAMESPACE) const auto result_is_ok = WIDE_INTEGER_NAMESPACE::math::wide_integer::example008a_miller_rabin_prime(); #else const auto result_is_ok = ::math::wide_integer::example008a_miller_rabin_prime(); #endif std::cout << "result_is_ok: " << std::boolalpha << result_is_ok << std::endl; return (result_is_ok ? 0 : -1); } #endif #if (BOOST_VERSION < 108000) #if ((defined(__clang__) && (__clang_major__ > 9)) && !defined(__APPLE__)) #pragma GCC diagnostic pop #endif #endif #if (defined(__GNUC__) && !defined(__clang__) && (__GNUC__ >= 12)) #pragma GCC diagnostic pop #pragma GCC diagnostic pop #endif #if (BOOST_VERSION < 108000) #if defined(__GNUC__) #pragma GCC diagnostic pop #pragma GCC diagnostic pop #pragma GCC diagnostic pop #endif #endif ================================================ FILE: examples/example008b_solovay_strassen_prime.cpp ================================================ /////////////////////////////////////////////////////////////////// // Copyright Christopher Kormanyos 2026. // // Distributed under the Boost Software License, // // Version 1.0. (See accompanying file LICENSE_1_0.txt // // or copy at http://www.boost.org/LICENSE_1_0.txt) // /////////////////////////////////////////////////////////////////// #include #include #include #include #include #include #include namespace local_solovay_strassen { namespace detail { template auto jacobi(UnsignedIntegerType a, UnsignedIntegerType n) -> int; template auto jacobi(UnsignedIntegerType a, UnsignedIntegerType n) -> int { // Calculate the integer's Jacobi symbol. // LCOV_EXCL_START if( ((static_cast(n) == 0U) && (n== 0U)) || ((static_cast(n) % 2U) == 0U)) { return 0; } // LCOV_EXCL_STOP a %= n; int result = 1; while(a != 0) { while((static_cast(a) % 2U) == 0U) { a /= 2U; UnsignedIntegerType r { n % 8U }; // NOLINT(cppcoreguidelines-avoid-magic-numbers,readability-magic-numbers) if( ((static_cast(r) == 3U) && (r == 3U)) // NOLINT(cppcoreguidelines-avoid-magic-numbers,readability-magic-numbers) || ((static_cast(r) == 5U) && (r == 5U))) // NOLINT(cppcoreguidelines-avoid-magic-numbers,readability-magic-numbers) { result = -result; } } std::swap(a, n); const unsigned a_mod_4 { static_cast(a % 4U) }; // NOLINT(cppcoreguidelines-avoid-magic-numbers,readability-magic-numbers) const unsigned n_mod_4 { static_cast(n % 4U) }; // NOLINT(cppcoreguidelines-avoid-magic-numbers,readability-magic-numbers) if((a_mod_4 == 3U) && (n_mod_4 == 3U)) // NOLINT(cppcoreguidelines-avoid-magic-numbers,readability-magic-numbers) { result = -result; } a %= n; } const bool n_is_one { ((static_cast(n) == 1U) && (n == 1U)) }; return (n_is_one ? result : 0); } } // namespace detail template auto solovay_strassen(const UnsignedIntegerType& n, const int iterations, DistributionType& distribution, GeneratorType& generator) -> bool; // NOLINT(readability-avoid-const-params-in-decls) template auto solovay_strassen(const UnsignedIntegerType& n, const int iterations, DistributionType& distribution, GeneratorType& generator) -> bool // NOLINT(readability-avoid-const-params-in-decls) { // Perform a Solovay-Strassen primality test. // If this ever goes to production, then testing a lot more semi-small // primes, as done in the library's Miller-Rabin, would make sense here. { const unsigned un { static_cast(n) }; if((un < 2U) && (n < 2U)) { return false; } if((un == 2U) && (n == 2U)) { return true; } if((un % 2U) == 0U) { return false; } } using local_wide_integer_type = UnsignedIntegerType; for(int i = 0; i < iterations; ++i) { local_wide_integer_type a { distribution(generator) }; local_wide_integer_type g = gcd(a, n); if((static_cast(g) > 1U) && (g > 1U)) { return false; } const int jac = detail::jacobi(a, n); if(jac == 0) { return false; } const local_wide_integer_type exponent { (n - 1) / 2 }; const local_wide_integer_type mod_exp { powm(a, exponent, n) }; const local_wide_integer_type jacobian { (jac == -1) ? (n - 1) : jac }; if(mod_exp != (jacobian % n)) { return false; } } // The candidate is probably prime. return true; } } // namespace local_solovay_strassen namespace local_example008b_solovay_strassen_prime { #if defined(WIDE_INTEGER_NAMESPACE) using wide_integer_type = WIDE_INTEGER_NAMESPACE::math::wide_integer::uintwide_t(UINT32_C(512))>; using distribution_type = WIDE_INTEGER_NAMESPACE::math::wide_integer::uniform_int_distribution; #else using wide_integer_type = ::math::wide_integer::uintwide_t(UINT32_C(512))>; using distribution_type = ::math::wide_integer::uniform_int_distribution; #endif using random_engine1_type = std::mt19937; using random_engine2_type = std::linear_congruential_engine; // NOLINT(cppcoreguidelines-avoid-magic-numbers,readability-magic-numbers) const auto seed_start = ::util::util_pseudorandom_time_point_seed::value(); // NOLINT(cert-err58-cpp) random_engine1_type gen1(static_cast(seed_start)); // NOLINT(cert-err58-cpp,cppcoreguidelines-avoid-non-const-global-variables) random_engine2_type gen2(static_cast(seed_start)); // NOLINT(cert-err58-cpp,cppcoreguidelines-avoid-non-const-global-variables) auto example008b_solovay_strassen_prime_run() -> bool; auto example008b_solovay_strassen_prime_run() -> bool { // Use a pseudo-random seed for this test. random_engine1_type generator1(util::util_pseudorandom_time_point_seed::value()); random_engine2_type generator2(util::util_pseudorandom_time_point_seed::value()); // Select prime candidates from a range of 10^150 ... max(uint512_t) - 1. constexpr wide_integer_type dist_min ( "1" "00000000000000000000000000000000000000000000000000" "00000000000000000000000000000000000000000000000000" "00000000000000000000000000000000000000000000000000" ); distribution_type dist1 { dist_min, (std::numeric_limits::max)() - 1 }; bool result_is_ok { false }; constexpr int max_trials { 8192 }; // NOLINT(cppcoreguidelines-avoid-magic-numbers,readability-magic-numbers) int trials { 0 }; for( ; trials < max_trials; ++trials) { // Perform a Solovay-Strassen versus Miller-Rabin primality comparison. // Each one should detect prime/non-prime with the same Boolean result // for a given prime candidate p0. #if defined(WIDE_INTEGER_NAMESPACE) using local_unsigned_fast_type = WIDE_INTEGER_NAMESPACE::math::wide_integer::unsigned_fast_type; #else using local_unsigned_fast_type = ::math::wide_integer::unsigned_fast_type; #endif constexpr local_unsigned_fast_type number_of_trials { UINT8_C(56) }; const wide_integer_type p0 { dist1(generator1) }; distribution_type dist2 { wide_integer_type { 2U }, p0 - 1 }; const bool result_solovay_strassen_is_prime = local_solovay_strassen::solovay_strassen ( p0, number_of_trials, dist2, generator2 ); const bool result_miller_rabin_ctrl_is_prime = miller_rabin ( p0, 25, dist2, generator2 ); result_is_ok = (result_solovay_strassen_is_prime == result_miller_rabin_ctrl_is_prime); if(result_solovay_strassen_is_prime) { break; } } result_is_ok = ((trials < max_trials) && result_is_ok); return result_is_ok; } } // namespace local_example008b_solovay_strassen_prime #if defined(WIDE_INTEGER_NAMESPACE) auto WIDE_INTEGER_NAMESPACE::math::wide_integer::example008b_solovay_strassen_prime() -> bool #else auto ::math::wide_integer::example008b_solovay_strassen_prime() -> bool #endif { bool result_is_ok { true }; for(auto i = static_cast(UINT8_C(0)); #if !defined(UINTWIDE_T_REDUCE_TEST_DEPTH) i < static_cast(UINT8_C(16)); #else i < static_cast(UINT8_C(4)); #endif ++i) { const auto result_prime_run_is_ok = local_example008b_solovay_strassen_prime::example008b_solovay_strassen_prime_run(); result_is_ok = (result_prime_run_is_ok && result_is_ok); } return result_is_ok; } // Enable this if you would like to activate this main() as a standalone example. #if defined(WIDE_INTEGER_STANDALONE_EXAMPLE008B_SOLOVAY_STRASSEN_PRIME) #include #include auto main() -> int // NOLINT(bugprone-exception-escape) { #if defined(WIDE_INTEGER_NAMESPACE) const auto result_is_ok = WIDE_INTEGER_NAMESPACE::math::wide_integer::example008b_solovay_strassen_prime(); #else const auto result_is_ok = ::math::wide_integer::example008b_solovay_strassen_prime(); #endif std::cout << "result_is_ok: " << std::boolalpha << result_is_ok << std::endl; return (result_is_ok ? 0 : -1); } #endif ================================================ FILE: examples/example009_timed_mul.cpp ================================================ /////////////////////////////////////////////////////////////////// // Copyright Christopher Kormanyos 2018 - 2025. // // Distributed under the Boost Software License, // // Version 1.0. (See accompanying file LICENSE_1_0.txt // // or copy at http://www.boost.org/LICENSE_1_0.txt) // /////////////////////////////////////////////////////////////////// #include #include #include #include #include #include #include #include #include #include #include #include namespace local_timed_mul { constexpr std::uint32_t wide_integer_test9_digits2 = static_cast(1ULL << 15U); template auto get_random_big_uint(RandomEngineType& rng, UnsignedIntegralIteratorType it_out) -> void { using local_uint_type = typename std::iterator_traits::value_type; #if defined(WIDE_INTEGER_NAMESPACE) using distribution_type = WIDE_INTEGER_NAMESPACE::math::wide_integer::uniform_int_distribution::digits, typename local_uint_type::limb_type>; #else using distribution_type = ::math::wide_integer::uniform_int_distribution::digits, typename local_uint_type::limb_type>; #endif distribution_type distribution; *it_out = distribution(rng); } #if defined(WIDE_INTEGER_NAMESPACE) using big_uint_type = WIDE_INTEGER_NAMESPACE::math::wide_integer::uintwide_t; #else using big_uint_type = ::math::wide_integer::uintwide_t; #endif auto local_a() -> std::vector&; auto local_a() -> std::vector& { static std::vector my_local_a ( static_cast::size_type>(UINT32_C(128)) ); return my_local_a; } auto local_b() -> std::vector&; auto local_b() -> std::vector& { static std::vector my_local_b(local_a().size()); return my_local_b; } } // namespace local_timed_mul #if defined(WIDE_INTEGER_NAMESPACE) auto WIDE_INTEGER_NAMESPACE::math::wide_integer::example009_timed_mul() -> bool #else auto ::math::wide_integer::example009_timed_mul() -> bool #endif { using random_engine_type = std::linear_congruential_engine; random_engine_type rng; // NOLINT(cert-msc32-c,cert-msc51-cpp) rng.seed(::util::util_pseudorandom_time_point_seed::value()); for(auto i = static_cast::size_type>(0U); i < local_timed_mul::local_a().size(); ++i) { local_timed_mul::get_random_big_uint(rng, local_timed_mul::local_a().begin() + static_cast::difference_type>(i)); local_timed_mul::get_random_big_uint(rng, local_timed_mul::local_b().begin() + static_cast::difference_type>(i)); } std::uint64_t count = 0U; std::size_t index = 0U; using stopwatch_type = concurrency::stopwatch; stopwatch_type my_stopwatch { }; while(stopwatch_type::elapsed_time(my_stopwatch) < static_cast(6.0L)) // NOLINT(cppcoreguidelines-avoid-magic-numbers,readability-magic-numbers) { local_timed_mul::local_a().at(index) * local_timed_mul::local_b().at(index); ++count; ++index; if(index >= local_timed_mul::local_a().size()) { index = 0U; } } const float kops_per_sec = static_cast(count) / static_cast(static_cast(stopwatch_type::elapsed_time(my_stopwatch) * 1000.0F)); { const auto flg = std::cout.flags(); std::cout << "bits: " << std::numeric_limits::digits << ", kops_per_sec: " << std::fixed << std::setprecision(3) << kops_per_sec << ", count: " << count << std::endl; std::cout.flags(flg); } const auto result_is_ok = (kops_per_sec > (std::numeric_limits::min)()); return result_is_ok; } // Enable this if you would like to activate this main() as a standalone example. #if defined(WIDE_INTEGER_STANDALONE_EXAMPLE009_TIMED_MUL) auto main() -> int { #if defined(WIDE_INTEGER_NAMESPACE) const auto result_is_ok = WIDE_INTEGER_NAMESPACE::math::wide_integer::example009_timed_mul(); #else const auto result_is_ok = ::math::wide_integer::example009_timed_mul(); #endif std::cout << "result_is_ok: " << std::boolalpha << result_is_ok << std::endl; return (result_is_ok ? 0 : -1); } #endif ================================================ FILE: examples/example009a_timed_mul_4_by_4.cpp ================================================ /////////////////////////////////////////////////////////////////// // Copyright Christopher Kormanyos 2018 - 2025. // // Distributed under the Boost Software License, // // Version 1.0. (See accompanying file LICENSE_1_0.txt // // or copy at http://www.boost.org/LICENSE_1_0.txt) // /////////////////////////////////////////////////////////////////// #include #include #include #include #include #include #include #include #include #include #include #include namespace local_timed_mul_4_by_4 { template auto get_random_big_uint(RandomEngineType& rng, UnsignedIntegralIteratorType it_out) -> void { using local_uint_type = typename std::iterator_traits::value_type; #if defined(WIDE_INTEGER_NAMESPACE) using distribution_type = WIDE_INTEGER_NAMESPACE::math::wide_integer::uniform_int_distribution::digits, typename local_uint_type::limb_type>; #else using distribution_type = ::math::wide_integer::uniform_int_distribution::digits, typename local_uint_type::limb_type>; #endif distribution_type distribution; *it_out = distribution(rng); } #if defined(WIDE_INTEGER_NAMESPACE) using big_uint_type = WIDE_INTEGER_NAMESPACE::math::wide_integer::uintwide_t(UINT32_C(128))>; #else using big_uint_type = ::math::wide_integer::uintwide_t(UINT32_C(128))>; #endif auto local_a() -> std::vector&; auto local_a() -> std::vector& { static std::vector my_local_a ( static_cast::size_type>(UINT32_C(1024)) ); return my_local_a; } auto local_b() -> std::vector&; auto local_b() -> std::vector& { static std::vector my_local_b(local_a().size()); return my_local_b; } } // namespace local_timed_mul_4_by_4 #if defined(WIDE_INTEGER_NAMESPACE) auto WIDE_INTEGER_NAMESPACE::math::wide_integer::example009a_timed_mul_4_by_4() -> bool #else auto ::math::wide_integer::example009a_timed_mul_4_by_4() -> bool #endif { using random_engine_type = std::linear_congruential_engine; random_engine_type rng; // NOLINT(cert-msc32-c,cert-msc51-cpp) rng.seed(::util::util_pseudorandom_time_point_seed::value()); for(auto i = static_cast::size_type>(0U); i < local_timed_mul_4_by_4::local_a().size(); ++i) { local_timed_mul_4_by_4::get_random_big_uint(rng, local_timed_mul_4_by_4::local_a().begin() + static_cast::difference_type>(i)); local_timed_mul_4_by_4::get_random_big_uint(rng, local_timed_mul_4_by_4::local_b().begin() + static_cast::difference_type>(i)); } std::uint64_t count = 0U; std::size_t index = 0U; using stopwatch_type = concurrency::stopwatch; stopwatch_type my_stopwatch { }; while(stopwatch_type::elapsed_time(my_stopwatch) < static_cast(6.0L)) // NOLINT(cppcoreguidelines-avoid-magic-numbers,readability-magic-numbers) { local_timed_mul_4_by_4::local_a().at(index + 0U) * local_timed_mul_4_by_4::local_b().at(index + 0U); local_timed_mul_4_by_4::local_a().at(index + 1U) * local_timed_mul_4_by_4::local_b().at(index + 1U); local_timed_mul_4_by_4::local_a().at(index + 2U) * local_timed_mul_4_by_4::local_b().at(index + 2U); local_timed_mul_4_by_4::local_a().at(index + 3U) * local_timed_mul_4_by_4::local_b().at(index + 3U); count += 4U; index += 4U; if(index >= local_timed_mul_4_by_4::local_a().size()) { index = 0U; } } const float kops_per_sec = static_cast(count) / static_cast(static_cast(stopwatch_type::elapsed_time(my_stopwatch) * 1000.0F)); { const auto flg = std::cout.flags(); std::cout << "bits: " << std::numeric_limits::digits << ", kops_per_sec: " << std::fixed << std::setprecision(2) << kops_per_sec << ", count: " << count << std::endl; std::cout.flags(flg); } const auto result_is_ok = (kops_per_sec > (std::numeric_limits::min)()); return result_is_ok; } // Enable this if you would like to activate this main() as a standalone example. #if defined(WIDE_INTEGER_STANDALONE_EXAMPLE009A_TIMED_MUL_4_BY_4) auto main() -> int { #if defined(WIDE_INTEGER_NAMESPACE) const auto result_is_ok = WIDE_INTEGER_NAMESPACE::math::wide_integer::example009a_timed_mul_4_by_4(); #else const auto result_is_ok = ::math::wide_integer::example009a_timed_mul_4_by_4(); #endif std::cout << "result_is_ok: " << std::boolalpha << result_is_ok << std::endl; return (result_is_ok ? 0 : -1); } #endif ================================================ FILE: examples/example009b_timed_mul_8_by_8.cpp ================================================ /////////////////////////////////////////////////////////////////// // Copyright Christopher Kormanyos 2018 - 2025. // // Distributed under the Boost Software License, // // Version 1.0. (See accompanying file LICENSE_1_0.txt // // or copy at http://www.boost.org/LICENSE_1_0.txt) // /////////////////////////////////////////////////////////////////// #include #include #include #include #include #include #include #include #include #include #include #include namespace local_timed_mul_8_by_8 { template auto get_random_big_uint(RandomEngineType& rng, UnsignedIntegralIteratorType it_out) -> void { using local_uint_type = typename std::iterator_traits::value_type; #if defined(WIDE_INTEGER_NAMESPACE) using distribution_type = WIDE_INTEGER_NAMESPACE::math::wide_integer::uniform_int_distribution::digits, typename local_uint_type::limb_type>; #else using distribution_type = ::math::wide_integer::uniform_int_distribution::digits, typename local_uint_type::limb_type>; #endif distribution_type distribution; *it_out = distribution(rng); } #if defined(WIDE_INTEGER_NAMESPACE) using big_uint_type = WIDE_INTEGER_NAMESPACE::math::wide_integer::uintwide_t(UINT32_C(256))>; #else using big_uint_type = ::math::wide_integer::uintwide_t(UINT32_C(256))>; #endif auto local_a() -> std::vector&; auto local_a() -> std::vector& { static std::vector my_local_a ( static_cast::size_type>(UINT32_C(1024)) ); return my_local_a; } auto local_b() -> std::vector&; auto local_b() -> std::vector& { static std::vector my_local_b(local_a().size()); return my_local_b; } } // namespace local_timed_mul_8_by_8 #if defined(WIDE_INTEGER_NAMESPACE) auto WIDE_INTEGER_NAMESPACE::math::wide_integer::example009b_timed_mul_8_by_8() -> bool #else auto ::math::wide_integer::example009b_timed_mul_8_by_8() -> bool #endif { using random_engine_type = std::linear_congruential_engine; random_engine_type rng; // NOLINT(cert-msc32-c,cert-msc51-cpp) rng.seed(::util::util_pseudorandom_time_point_seed::value()); for(auto i = static_cast::size_type>(0U); i < local_timed_mul_8_by_8::local_a().size(); ++i) { local_timed_mul_8_by_8::get_random_big_uint(rng, local_timed_mul_8_by_8::local_a().begin() + static_cast::difference_type>(i)); local_timed_mul_8_by_8::get_random_big_uint(rng, local_timed_mul_8_by_8::local_b().begin() + static_cast::difference_type>(i)); } std::uint64_t count = 0U; std::size_t index = 0U; using stopwatch_type = concurrency::stopwatch; stopwatch_type my_stopwatch { }; while(stopwatch_type::elapsed_time(my_stopwatch) < static_cast(6.0L)) // NOLINT(cppcoreguidelines-avoid-magic-numbers,readability-magic-numbers) { local_timed_mul_8_by_8::local_a().at(index + 0U) * local_timed_mul_8_by_8::local_b().at(index + 0U); local_timed_mul_8_by_8::local_a().at(index + 1U) * local_timed_mul_8_by_8::local_b().at(index + 1U); local_timed_mul_8_by_8::local_a().at(index + 2U) * local_timed_mul_8_by_8::local_b().at(index + 2U); local_timed_mul_8_by_8::local_a().at(index + 3U) * local_timed_mul_8_by_8::local_b().at(index + 3U); count += 4U; index += 4U; if(index >= local_timed_mul_8_by_8::local_a().size()) { index = 0U; } } const float kops_per_sec = static_cast(count) / static_cast(static_cast(stopwatch_type::elapsed_time(my_stopwatch) * 1000.0F)); { const auto flg = std::cout.flags(); std::cout << "bits: " << std::numeric_limits::digits << ", kops_per_sec: " << std::fixed << std::setprecision(2) << kops_per_sec << ", count: " << count << std::endl; std::cout.flags(flg); } const auto result_is_ok = (kops_per_sec > (std::numeric_limits::min)()); return result_is_ok; } // Enable this if you would like to activate this main() as a standalone example. #if defined(WIDE_INTEGER_STANDALONE_EXAMPLE009B_TIMED_MUL_8_BY_8) auto main() -> int { #if defined(WIDE_INTEGER_NAMESPACE) const auto result_is_ok = WIDE_INTEGER_NAMESPACE::math::wide_integer::example009b_timed_mul_8_by_8(); #else const auto result_is_ok = ::math::wide_integer::example009b_timed_mul_8_by_8(); #endif std::cout << "result_is_ok: " << std::boolalpha << result_is_ok << std::endl; return (result_is_ok ? 0 : -1); } #endif ================================================ FILE: examples/example010_uint48_t.cpp ================================================ /////////////////////////////////////////////////////////////////// // Copyright Christopher Kormanyos 2018 - 2025. // // Distributed under the Boost Software License, // // Version 1.0. (See accompanying file LICENSE_1_0.txt // // or copy at http://www.boost.org/LICENSE_1_0.txt) // /////////////////////////////////////////////////////////////////// #include #include #include #if defined(WIDE_INTEGER_NAMESPACE) auto WIDE_INTEGER_NAMESPACE::math::wide_integer::example010_uint48_t() -> bool #else auto ::math::wide_integer::example010_uint48_t() -> bool #endif { #if defined(WIDE_INTEGER_NAMESPACE) using uint48_t = WIDE_INTEGER_NAMESPACE::math::wide_integer::uintwide_t(UINT32_C(48)), std::uint8_t>; #else using uint48_t = ::math::wide_integer::uintwide_t(UINT32_C(48)), std::uint8_t>; #endif #if defined(WIDE_INTEGER_NAMESPACE) using distribution_type = WIDE_INTEGER_NAMESPACE::math::wide_integer::uniform_int_distribution(UINT32_C(48)), typename uint48_t::limb_type>; #else using distribution_type = ::math::wide_integer::uniform_int_distribution(UINT32_C(48)), typename uint48_t::limb_type>; #endif using random_engine_type = std::linear_congruential_engine; random_engine_type generator(static_cast(UINT32_C(0xF00DCAFE))); // NOLINT(cert-msc32-c,cert-msc51-cpp,cppcoreguidelines-avoid-magic-numbers,readability-magic-numbers) distribution_type distribution; const auto a64 = static_cast(distribution(generator)); const auto b64 = static_cast(distribution(generator)); const uint48_t a(a64); const uint48_t b(b64); const uint48_t c_add = (a + b); const uint48_t c_sub = (a - b); const uint48_t c_mul = (a * b); const uint48_t c_div = (a / b); const auto result_is_ok = ( ( (c_add == static_cast((a64 + b64) & static_cast(UINT64_C(0x0000FFFFFFFFFFFF)))) && (c_sub == static_cast((a64 - b64) & static_cast(UINT64_C(0x0000FFFFFFFFFFFF)))) && (c_mul == static_cast((a64 * b64) & static_cast(UINT64_C(0x0000FFFFFFFFFFFF)))) && (c_div == static_cast((a64 / b64) & static_cast(UINT64_C(0x0000FFFFFFFFFFFF))))) && ( (static_cast(c_add) == static_cast((a64 + b64) & static_cast(UINT64_C(0x0000FFFFFFFFFFFF)))) && (static_cast(c_sub) == static_cast((a64 - b64) & static_cast(UINT64_C(0x0000FFFFFFFFFFFF)))) && (static_cast(c_mul) == static_cast((a64 * b64) & static_cast(UINT64_C(0x0000FFFFFFFFFFFF)))) && (static_cast(c_div) == static_cast((a64 / b64) & static_cast(UINT64_C(0x0000FFFFFFFFFFFF)))))); return result_is_ok; } // Enable this if you would like to activate this main() as a standalone example. #if defined(WIDE_INTEGER_STANDALONE_EXAMPLE010_UINT48_T) #include #include auto main() -> int { #if defined(WIDE_INTEGER_NAMESPACE) const auto result_is_ok = WIDE_INTEGER_NAMESPACE::math::wide_integer::example010_uint48_t(); #else const auto result_is_ok = ::math::wide_integer::example010_uint48_t(); #endif std::cout << "result_is_ok: " << std::boolalpha << result_is_ok << std::endl; return (result_is_ok ? 0 : -1); } #endif ================================================ FILE: examples/example011_uint24_t.cpp ================================================ /////////////////////////////////////////////////////////////////// // Copyright Christopher Kormanyos 2018 - 2025. // // Distributed under the Boost Software License, // // Version 1.0. (See accompanying file LICENSE_1_0.txt // // or copy at http://www.boost.org/LICENSE_1_0.txt) // /////////////////////////////////////////////////////////////////// #include #include #include #if defined(WIDE_INTEGER_NAMESPACE) auto WIDE_INTEGER_NAMESPACE::math::wide_integer::example011_uint24_t() -> bool #else auto ::math::wide_integer::example011_uint24_t() -> bool #endif { #if defined(WIDE_INTEGER_NAMESPACE) using uint24_t = WIDE_INTEGER_NAMESPACE::math::wide_integer::uintwide_t(UINT32_C(24)), std::uint8_t>; #else using uint24_t = ::math::wide_integer::uintwide_t(UINT32_C(24)), std::uint8_t>; #endif #if defined(WIDE_INTEGER_NAMESPACE) using distribution_type = WIDE_INTEGER_NAMESPACE::math::wide_integer::uniform_int_distribution(UINT32_C(24)), typename uint24_t::limb_type>; #else using distribution_type = ::math::wide_integer::uniform_int_distribution(UINT32_C(24)), typename uint24_t::limb_type>; #endif using random_engine_type = std::linear_congruential_engine; random_engine_type generator(UINT32_C(0xDEADBEEF)); // NOLINT(cert-msc32-c,cert-msc51-cpp) distribution_type distribution; const auto a32 = static_cast(distribution(generator)); const auto b32 = static_cast(distribution(generator)); const uint24_t a(a32); const uint24_t b(b32); const uint24_t c_add = (a + b); const uint24_t c_sub = (a - b); const uint24_t c_mul = (a * b); const uint24_t c_div = (a / b); const auto result_is_ok = ( ( (c_add == static_cast(static_cast(a32 + b32) & UINT32_C(0x00FFFFFF))) && (c_sub == static_cast(static_cast(a32 - b32) & UINT32_C(0x00FFFFFF))) && (c_mul == static_cast(static_cast(a32 * b32) & UINT32_C(0x00FFFFFF))) && (c_div == static_cast(static_cast(a32 / b32) & UINT32_C(0x00FFFFFF)))) && ( (static_cast(c_add) == static_cast(static_cast(a32 + b32) & UINT32_C(0x00FFFFFF))) && (static_cast(c_sub) == static_cast(static_cast(a32 - b32) & UINT32_C(0x00FFFFFF))) && (static_cast(c_mul) == static_cast(static_cast(a32 * b32) & UINT32_C(0x00FFFFFF))) && (static_cast(c_div) == static_cast(static_cast(a32 / b32) & UINT32_C(0x00FFFFFF))))); return result_is_ok; } // Enable this if you would like to activate this main() as a standalone example. #if defined(WIDE_INTEGER_STANDALONE_EXAMPLE011_UINT24_T) #include #include auto main() -> int { #if defined(WIDE_INTEGER_NAMESPACE) const auto result_is_ok = WIDE_INTEGER_NAMESPACE::math::wide_integer::example011_uint24_t(); #else const auto result_is_ok = ::math::wide_integer::example011_uint24_t(); #endif std::cout << "result_is_ok: " << std::boolalpha << result_is_ok << std::endl; return (result_is_ok ? 0 : -1); } #endif ================================================ FILE: examples/example012_rsa_crypto.cpp ================================================ /////////////////////////////////////////////////////////////////// // Copyright Christopher Kormanyos 2021 - 2025. // // Distributed under the Boost Software License, // // Version 1.0. (See accompanying file LICENSE_1_0.txt // // or copy at http://www.boost.org/LICENSE_1_0.txt) // /////////////////////////////////////////////////////////////////// #include #include #include #include #include namespace local_rsa { template> class rsa_base { public: static constexpr std::size_t bit_count = RsaBitCount; using allocator_type = typename std::allocator_traits::template rebind_alloc; #if defined(WIDE_INTEGER_NAMESPACE) using my_uintwide_t = WIDE_INTEGER_NAMESPACE::math::wide_integer::uintwide_t(bit_count), LimbType, allocator_type>; #else using my_uintwide_t = ::math::wide_integer::uintwide_t(bit_count), LimbType, allocator_type>; #endif using limb_type = typename my_uintwide_t::limb_type; using crypto_char = my_uintwide_t; using crypto_alloc = typename std::allocator_traits::template rebind_alloc; #if defined(WIDE_INTEGER_NAMESPACE) using crypto_string = WIDE_INTEGER_NAMESPACE::math::wide_integer::detail::dynamic_array; #else using crypto_string = ::math::wide_integer::detail::dynamic_array; #endif using private_key_type = struct { my_uintwide_t s; my_uintwide_t p; my_uintwide_t q; }; using public_key_type = struct public_key_type { my_uintwide_t r; my_uintwide_t m; }; virtual ~rsa_base() = default; struct euclidean { template static auto extended_euclidean(const IntegerType& a, // NOLINT(misc-no-recursion) const IntegerType& b, IntegerType* x, // NOLINT(bugprone-easily-swappable-parameters) IntegerType* y) -> IntegerType { // Recursive extended Euclidean algorithm. using local_integer_type = IntegerType; if(a == 0) { *x = local_integer_type { 0U }; *y = local_integer_type { 1U }; return b; } local_integer_type tmp_x { }; local_integer_type tmp_y { }; local_integer_type gcd_ext = extended_euclidean(b % a, a, &tmp_x, &tmp_y); *x = std::move(tmp_y - ((b / a) * tmp_x)); *y = std::move(tmp_x); return gcd_ext; } }; class encryptor { public: explicit encryptor(const public_key_type& key) : public_key(key) { } template auto encrypt(InputIterator in_first, const std::size_t count, OutputIterator out) -> void { for(auto it = in_first; it != in_first + static_cast::difference_type>(count); ++it) // NOLINT(altera-id-dependent-backward-branch) { *out++ = powm(my_uintwide_t(*it), public_key.r, public_key.m); } } private: const public_key_type& public_key; // NOLINT(readability-identifier-naming,cppcoreguidelines-avoid-const-or-ref-data-members) }; class decryptor { public: explicit decryptor(const private_key_type& key) : private_key(key) { } template auto decrypt(InputIterator cry_in, const std::size_t count, OutputIterator cypher_out) -> void { InputIterator cry_end(cry_in + static_cast::difference_type>(count)); for(auto it = cry_in; it != cry_end; ++it) // NOLINT(altera-id-dependent-backward-branch) { const my_uintwide_t tmp = powm(*it, private_key.s, private_key.q * private_key.p); *cypher_out++ = static_cast::value_type>(static_cast(tmp)); } } private: const private_key_type& private_key; // NOLINT(readability-identifier-naming,cppcoreguidelines-avoid-const-or-ref-data-members) }; rsa_base(const rsa_base& other) : my_p (other.my_p), my_q (other.my_q), my_r (other.my_r), my_m (other.my_m), phi_of_m (other.phi_of_m), public_key (other.public_key), private_key(other.private_key) { } rsa_base(rsa_base&& other) noexcept : my_p (static_cast(other.my_p)), my_q (static_cast(other.my_q)), my_r (static_cast(other.my_r)), my_m (static_cast(other.my_m)), phi_of_m (static_cast(other.phi_of_m)), public_key (static_cast(other.public_key)), private_key(static_cast(other.private_key)) { } auto operator=(const rsa_base& other) -> rsa_base& { if(this != &other) { my_p = other.my_p; my_q = other.my_q; my_r = other.my_r; my_m = other.my_m; phi_of_m = other.phi_of_m; public_key = other.public_key; private_key = other.private_key; } return *this; } auto operator=(rsa_base&& other) noexcept -> rsa_base& { my_p = static_cast(other.my_p); my_q = static_cast(other.my_q); my_r = static_cast(other.my_r); my_m = static_cast(other.my_m); phi_of_m = static_cast(other.phi_of_m); public_key = static_cast(other.public_key); private_key = static_cast(other.private_key); return *this; } auto getPublicKey () const -> const public_key_type& { return public_key; } // NOLINT(readability-identifier-naming) auto getPrivateKey() const -> const private_key_type& { return private_key; } // NOLINT(readability-identifier-naming) auto get_p() const -> const crypto_char& { return getPrivateKey().p; } auto get_q() const -> const crypto_char& { return getPrivateKey().q; } auto get_d() const -> const crypto_char& { return getPrivateKey().s; } auto get_n() const -> const crypto_char& { return getPublicKey().m; } auto encrypt(const std::string& str) const -> crypto_string { crypto_string str_out(str.length()); encryptor(public_key).encrypt(str.cbegin(), str.length(), str_out.begin()); return str_out; } // LCOV_EXCL_LINE auto decrypt(const crypto_string& str) const -> std::string { std::string res(str.size(), '\0'); decryptor(private_key).decrypt(str.cbegin(), str.size(), res.begin()); return res; } template static auto is_prime(const my_uintwide_t& p, const RandomEngineType& generator = RandomEngineType(util::util_pseudorandom_time_point_seed::value())) -> bool { #if defined(WIDE_INTEGER_NAMESPACE) using local_distribution_type = WIDE_INTEGER_NAMESPACE::math::wide_integer::uniform_int_distribution; #else using local_distribution_type = ::math::wide_integer::uniform_int_distribution(bit_count), limb_type, allocator_type>; #endif local_distribution_type distribution; RandomEngineType local_generator(generator); const bool miller_rabin_result_is_ok = miller_rabin(p, 25U, distribution, local_generator); return miller_rabin_result_is_ok; } rsa_base() = delete; protected: my_uintwide_t my_p; // NOLINT(cppcoreguidelines-non-private-member-variables-in-classes,misc-non-private-member-variables-in-classes,readability-identifier-naming) my_uintwide_t my_q; // NOLINT(cppcoreguidelines-non-private-member-variables-in-classes,misc-non-private-member-variables-in-classes,readability-identifier-naming) my_uintwide_t my_r; // NOLINT(cppcoreguidelines-non-private-member-variables-in-classes,misc-non-private-member-variables-in-classes,readability-identifier-naming) my_uintwide_t my_m; // NOLINT(cppcoreguidelines-non-private-member-variables-in-classes,misc-non-private-member-variables-in-classes,readability-identifier-naming) my_uintwide_t phi_of_m { }; // NOLINT(cppcoreguidelines-non-private-member-variables-in-classes,misc-non-private-member-variables-in-classes,readability-identifier-naming) public_key_type public_key { }; // NOLINT(cppcoreguidelines-non-private-member-variables-in-classes,misc-non-private-member-variables-in-classes,readability-identifier-naming) private_key_type private_key { }; // NOLINT(cppcoreguidelines-non-private-member-variables-in-classes,misc-non-private-member-variables-in-classes,readability-identifier-naming) rsa_base(my_uintwide_t p_in, my_uintwide_t q_in, my_uintwide_t r_in) : my_p(std::move(p_in)), my_q(std::move(q_in)), my_r(std::move(r_in)), my_m(my_p * my_q) { public_key = public_key_type { my_r, my_m }; // NOLINT(cppcoreguidelines-prefer-member-initializer) } auto calculate_private_key() -> void { my_uintwide_t a { phi_of_m }; my_uintwide_t b { my_r }; my_uintwide_t x { }; my_uintwide_t s { }; euclidean::extended_euclidean(a, b, &x, &s); if(is_neg(s)) { s = std::move(make_positive(s, phi_of_m)); } private_key = std::move( private_key_type { std::move(s), my_p, my_q } ); } private: static auto is_neg(const my_uintwide_t& x) -> bool { const bool x_is_neg = ((x & (my_uintwide_t(1U) << (std::numeric_limits::digits - 1))) != 0); return x_is_neg; } static auto make_positive(const my_uintwide_t& number, const my_uintwide_t& modulus) -> my_uintwide_t // NOLINT(bugprone-easily-swappable-parameters) { my_uintwide_t tmp = number; while(is_neg(tmp)) // NOLINT(altera-id-dependent-backward-branch) { tmp += modulus; } return tmp; } }; template class rsa_fips : public rsa_base { private: using base_class_type = rsa_base; public: rsa_fips(const typename base_class_type::my_uintwide_t& p_in, const typename base_class_type::my_uintwide_t& q_in, const typename base_class_type::my_uintwide_t& r_in) : base_class_type(p_in, q_in, r_in) { const typename base_class_type::my_uintwide_t my_one(1U); base_class_type::phi_of_m = lcm(base_class_type::my_p - my_one, base_class_type::my_q - my_one); base_class_type::calculate_private_key(); } rsa_fips(const rsa_fips& other) : base_class_type(other) { } rsa_fips(rsa_fips&& other) noexcept : base_class_type(other) { } ~rsa_fips() override = default; auto operator=(const rsa_fips& other) -> rsa_fips& // NOLINT(cert-oop54-cpp) { static_cast(base_class_type::operator=(other)); return *this; } auto operator=(rsa_fips&& other) noexcept -> rsa_fips& { static_cast(base_class_type::operator=(other)); return *this; } }; template class rsa_traditional : public rsa_base { private: using base_class_type = rsa_base; public: rsa_traditional(const typename base_class_type::my_uintwide_t& p_in, const typename base_class_type::my_uintwide_t& q_in, const typename base_class_type::my_uintwide_t& r_in) : base_class_type(p_in, q_in, r_in) { const typename base_class_type::my_uintwide_t my_one(1U); base_class_type::phi_of_m = ( (base_class_type::my_p - my_one) * (base_class_type::my_q - my_one)); base_class_type::calculate_private_key(); } rsa_traditional(const rsa_traditional& other) : base_class_type(other) { } rsa_traditional(rsa_traditional&& other) noexcept : base_class_type(other) { } virtual ~rsa_traditional() = default; auto operator=(const rsa_traditional& other) -> rsa_traditional& // NOLINT(cert-oop54-cpp) { static_cast(base_class_type::operator=(other)); return *this; } auto operator=(rsa_traditional&& other) noexcept -> rsa_traditional& { static_cast(base_class_type::operator=(other)); return *this; } }; } // namespace local_rsa #if defined(WIDE_INTEGER_NAMESPACE) auto WIDE_INTEGER_NAMESPACE::math::wide_integer::example012_rsa_crypto() -> bool #else auto ::math::wide_integer::example012_rsa_crypto() -> bool #endif { // Consider lines 25-30 in the file "KeyGen_186-3.rsp". // e = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000001 // seed = e5f707e49c4e7cc8fb202b5cd957963713f1c4726677c09b6a7f5dfe // p = ff03b1a74827c746db83d2eaff00067622f545b62584321256e62b01509f10962f9c5c8fd0b7f5184a9ce8e81f439df47dda14563dd55a221799d2aa57ed2713271678a5a0b8b40a84ad13d5b6e6599e6467c670109cf1f45ccfed8f75ea3b814548ab294626fe4d14ff764dd8b091f11a0943a2dd2b983b0df02f4c4d00b413 // q = dacaabc1dc57faa9fd6a4274c4d588765a1d3311c22e57d8101431b07eb3ddcb05d77d9a742ac2322fe6a063bd1e05acb13b0fe91c70115c2b1eee1155e072527011a5f849de7072a1ce8e6b71db525fbcda7a89aaed46d27aca5eaeaf35a26270a4a833c5cda681ffd49baa0f610bad100cdf47cc86e5034e2a0b2179e04ec7 // n = d9f3094b36634c05a02ae1a5569035107a48029e39b3c6a1853817f063e18e761c0c538e55ff2c7e53d603bb35cabb3b8d07f82aa0afdeaf7441fcf6746c5bcaaa2cde398ad73edb9c340c3ffca559132581eaf8f65c13d02f3445a932a3e1fadb5912f7553edec5047e4d0ed06ee87effc549e194d38e06b73a971c961688ba2d4aa4f450d2523372f317d41d06f9f0360e962ce953a69f36c53c370799fcfba195e8f691ebe862f84ae4bbd7747bc14499bd0efffcdc7154325908355c2ffc5b3948b8102b33aa2420381470e4ee858380ff0eea58288516c263f6d51dbbd0e477d1393a0a3ee60e1fde4330856665bf522006608a6104c138c0f39e09c4c5 // d = 1bf009caddc664b4404d59711fde16d7c55822449de1c5a084d22ed5791fdaa37ea538867fc91a17e6856e277c2dedd70ca8bf6ec44b0e729917a88e5988cc561d948ddeea46e21fd8ff46cce7657c94bfb1bdf40b3b30d4595a8bc3a15f1d4ad4c665c09b3b265ba19cdb0b89cbaadd0097ff52e9f6e594f86829c5bb4e9ba0200f12fa6dc60fd28dec0d194f08deb50f5a7749540160d6e8338e75b11165b76f4650c2fcce08f979ad9941daedaa5e328473bf712f8f549c36967f5e15477dc643d1f48d563139134e5cdc4bb84f9782cd5125e864e067cb980290f215cb41090e297bac2714efba61115d85613851c2de50a82f4ab526b88c61b7c9a0b589 using rsa_type = local_rsa::rsa_fips(UINT32_C(2048))>; using rsa_integral_type = typename rsa_type::my_uintwide_t; const rsa_integral_type p("0xFF03B1A74827C746DB83D2EAFF00067622F545B62584321256E62B01509F10962F9C5C8FD0B7F5184A9CE8E81F439DF47DDA14563DD55A221799D2AA57ED2713271678A5A0B8B40A84AD13D5B6E6599E6467C670109CF1F45CCFED8F75EA3B814548AB294626FE4D14FF764DD8B091F11A0943A2DD2B983B0DF02F4C4D00B413"); const rsa_integral_type q("0xDACAABC1DC57FAA9FD6A4274C4D588765A1D3311C22E57D8101431B07EB3DDCB05D77D9A742AC2322FE6A063BD1E05ACB13B0FE91C70115C2B1EEE1155E072527011A5F849DE7072A1CE8E6B71DB525FBCDA7A89AAED46D27ACA5EAEAF35A26270A4A833C5CDA681FFD49BAA0F610BAD100CDF47CC86E5034E2A0B2179E04EC7"); const rsa_integral_type e("0x100000001"); const rsa_integral_type n("0xD9F3094B36634C05A02AE1A5569035107A48029E39B3C6A1853817F063E18E761C0C538E55FF2C7E53D603BB35CABB3B8D07F82AA0AFDEAF7441FCF6746C5BCAAA2CDE398AD73EDB9C340C3FFCA559132581EAF8F65C13D02F3445A932A3E1FADB5912F7553EDEC5047E4D0ED06EE87EFFC549E194D38E06B73A971C961688BA2D4AA4F450D2523372F317D41D06F9F0360E962CE953A69F36C53C370799FCFBA195E8F691EBE862F84AE4BBD7747BC14499BD0EFFFCDC7154325908355C2FFC5B3948B8102B33AA2420381470E4EE858380FF0EEA58288516C263F6D51DBBD0E477D1393A0A3EE60E1FDE4330856665BF522006608A6104C138C0F39E09C4C5"); const rsa_integral_type d("0x1BF009CADDC664B4404D59711FDE16D7C55822449DE1C5A084D22ED5791FDAA37EA538867FC91A17E6856E277C2DEDD70CA8BF6EC44B0E729917A88E5988CC561D948DDEEA46E21FD8FF46CCE7657C94BFB1BDF40B3B30D4595A8BC3A15F1D4AD4C665C09B3B265BA19CDB0B89CBAADD0097FF52E9F6E594F86829C5BB4E9BA0200F12FA6DC60FD28DEC0D194F08DEB50F5A7749540160D6E8338E75B11165B76F4650C2FCCE08F979AD9941DAEDAA5E328473BF712F8F549C36967F5E15477DC643D1F48D563139134E5CDC4BB84F9782CD5125E864E067CB980290F215CB41090E297BAC2714EFBA61115D85613851C2DE50A82F4AB526B88C61B7C9A0B589"); bool result_is_ok = true; { using local_random_engine_type = std::mt19937; local_random_engine_type generator(::util::util_pseudorandom_time_point_seed::value()); const bool p_is_prime = rsa_type::is_prime(p, generator); result_is_ok = (p_is_prime && result_is_ok); } result_is_ok = (rsa_type::is_prime(q) && result_is_ok); const rsa_type rsa(p, q, e); result_is_ok = (( (rsa.get_p() == p) && (rsa.get_q() == q) && (rsa.get_d() == d)) && result_is_ok); result_is_ok = ((n == (p * q)) && result_is_ok); result_is_ok = ((n == rsa.get_n()) && result_is_ok); // Select "abc" as the sample string to encrypt. const std::string in_str("abc"); const typename rsa_type::crypto_string out_str = rsa.encrypt(in_str); const std::string res_str = rsa.decrypt(out_str); const auto res_ch_a_manual = static_cast(static_cast(powm(out_str[0U], d, n))); const auto res_ch_b_manual = static_cast(static_cast(powm(out_str[1U], d, n))); const auto res_ch_c_manual = static_cast(static_cast(powm(out_str[2U], d, n))); result_is_ok = ((res_str == "abc") && result_is_ok); result_is_ok = ((res_ch_a_manual == 'a') && result_is_ok); result_is_ok = ((res_ch_b_manual == 'b') && result_is_ok); result_is_ok = ((res_ch_c_manual == 'c') && result_is_ok); return result_is_ok; } // Enable this if you would like to activate this main() as a standalone example. #if defined(WIDE_INTEGER_STANDALONE_EXAMPLE012_RSA_CRYPTO) #include #include auto main() -> int { #if defined(WIDE_INTEGER_NAMESPACE) const auto result_is_ok = WIDE_INTEGER_NAMESPACE::math::wide_integer::example012_rsa_crypto(); #else const auto result_is_ok = ::math::wide_integer::example012_rsa_crypto(); #endif std::cout << "result_is_ok: " << std::boolalpha << result_is_ok << std::endl; return (result_is_ok ? 0 : -1); } #endif ================================================ FILE: examples/example013_ecdsa_sign_verify.cpp ================================================ /////////////////////////////////////////////////////////////////// // Copyright Christopher Kormanyos 2023 - 2025. // // Distributed under the Boost Software License, // // Version 1.0. (See accompanying file LICENSE_1_0.txt // // or copy at http://www.boost.org/LICENSE_1_0.txt) // /////////////////////////////////////////////////////////////////// // This work uses (significantly) translated and modified parts // of andreacorbellini/ecc // see also: https://github.com/andreacorbellini/ecc // and also: https://github.com/andreacorbellini/ecc/blob/master/scripts/ecdsa.py // Full original andreacorbellini/ecc copyright information follows. /*---------------------------------------------------------------------------- The MIT License (MIT) Copyright (c) 2015 Andrea Corbellini Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -----------------------------------------------------------------------------*/ // For algorithm description of ECDSA, please consult also: // D. Hankerson, A. Menezes, S. Vanstone, "Guide to Elliptic // Curve Cryptography", Springer 2004, Chapter 4, in particular // Algorithm 4.24 (keygen on page 180), and Algorithms 4.29 and 4.30. // Complete descriptions of sign/verify are featured on page 184. // For another algorithm description of ECDSA, // see also: https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.186-5.pdf // For algorithm description of SHA-2 HASH-256, // see also: https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.180-4.pdf // The SHA-2 HASH-256 implementation has been taken (with slight modification) // from: https://github.com/imahjoub/hash_sha256 #include #include #include #include #include #include #include #include namespace example013_ecdsa { #if defined(WIDE_INTEGER_NAMESPACE) using WIDE_INTEGER_NAMESPACE::math::wide_integer::detail::fill_unsafe; #else using ::math::wide_integer::detail::fill_unsafe; #endif class hash_sha256 { private: #if defined(WIDE_INTEGER_NAMESPACE) using transform_context_type = WIDE_INTEGER_NAMESPACE::math::wide_integer::detail::array_detail::array(UINT8_C(8))>; using data_array_type = WIDE_INTEGER_NAMESPACE::math::wide_integer::detail::array_detail::array(UINT8_C(64))>; #else using transform_context_type = ::math::wide_integer::detail::array_detail::array(UINT8_C(8))>; using data_array_type = ::math::wide_integer::detail::array_detail::array(UINT8_C(64))>; #endif using data_array_size_type = typename data_array_type::size_type; using transform_context_size_type = typename transform_context_type::size_type; public: #if defined(WIDE_INTEGER_NAMESPACE) using result_type = WIDE_INTEGER_NAMESPACE::math::wide_integer::detail::array_detail::array(UINT8_C(32))>; #else using result_type = ::math::wide_integer::detail::array_detail::array(UINT8_C(32))>; #endif // LCOV_EXCL_START constexpr hash_sha256() = default; constexpr hash_sha256(const hash_sha256&) = default; constexpr hash_sha256(hash_sha256&&) noexcept = default; ~hash_sha256() = default; constexpr auto operator=(hash_sha256&&) noexcept -> hash_sha256& = default; constexpr auto operator=(const hash_sha256&) -> hash_sha256& = default; // LCOV_EXCL_STOP constexpr auto hash(const std::uint8_t* msg, const size_t length) -> result_type { init(); update(msg, length); return finalize(); } constexpr void init() { my_datalen = static_cast(UINT8_C(0)); my_bitlen = static_cast(UINT8_C(0)); transform_context[static_cast(UINT8_C(0))] = static_cast(UINT32_C(0x6A09E667)); transform_context[static_cast(UINT8_C(1))] = static_cast(UINT32_C(0xBB67AE85)); transform_context[static_cast(UINT8_C(2))] = static_cast(UINT32_C(0x3C6EF372)); transform_context[static_cast(UINT8_C(3))] = static_cast(UINT32_C(0xA54FF53A)); transform_context[static_cast(UINT8_C(4))] = static_cast(UINT32_C(0x510E527F)); transform_context[static_cast(UINT8_C(5))] = static_cast(UINT32_C(0x9B05688C)); transform_context[static_cast(UINT8_C(6))] = static_cast(UINT32_C(0x1F83D9AB)); transform_context[static_cast(UINT8_C(7))] = static_cast(UINT32_C(0x5BE0CD19)); } constexpr void update(const std::uint8_t* msg, const size_t length) { for (auto i = static_cast(UINT8_C(0)); i < length; ++i) { my_data[static_cast(my_datalen)] = msg[i]; // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic,cppcoreguidelines-pro-bounds-constant-array-index) my_datalen++; if(my_datalen == static_cast(UINT8_C(64))) { // LCOV_EXCL_START sha256_transform(); my_datalen = static_cast(UINT8_C(0)); my_bitlen = static_cast(my_bitlen + static_cast(UINT16_C(512))); // LCOV_EXCL_STOP } } } constexpr auto finalize() -> result_type { result_type hash_result { }; auto hash_index = static_cast(my_datalen); my_data[static_cast(hash_index)] = static_cast(UINT8_C(0x80)); // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic,cppcoreguidelines-pro-bounds-constant-array-index) ++hash_index; // Pad whatever data is left in the buffer. if(my_datalen < static_cast(UINT8_C(56U))) { fill_unsafe((my_data.begin() + hash_index), (my_data.begin() + static_cast(UINT8_C(56))), static_cast(UINT8_C(0))); } else { // LCOV_EXCL_START fill_unsafe((my_data.begin() + hash_index), my_data.end(), static_cast(UINT8_C(0))); sha256_transform(); fill_unsafe(my_data.begin(), my_data.begin() + static_cast(UINT8_C(56)), static_cast(UINT8_C(0))); // LCOV_EXCL_STOP } // Append to the padding the total message length (in bits) and subsequently transform. my_bitlen = static_cast ( my_bitlen + static_cast ( static_cast(my_datalen) * static_cast(UINT8_C(8)) ) ); my_data[static_cast(UINT8_C(63))] = static_cast(my_bitlen >> static_cast(UINT8_C( 0))); my_data[static_cast(UINT8_C(62))] = static_cast(my_bitlen >> static_cast(UINT8_C( 8))); my_data[static_cast(UINT8_C(61))] = static_cast(my_bitlen >> static_cast(UINT8_C(16))); my_data[static_cast(UINT8_C(60))] = static_cast(my_bitlen >> static_cast(UINT8_C(24))); my_data[static_cast(UINT8_C(59))] = static_cast(my_bitlen >> static_cast(UINT8_C(32))); my_data[static_cast(UINT8_C(58))] = static_cast(my_bitlen >> static_cast(UINT8_C(40))); my_data[static_cast(UINT8_C(57))] = static_cast(my_bitlen >> static_cast(UINT8_C(48))); my_data[static_cast(UINT8_C(56))] = static_cast(my_bitlen >> static_cast(UINT8_C(56))); sha256_transform(); // Since this implementation uses little endian byte ordering and SHA uses big endian, // reverse all the bytes when copying the final transform_context to the output hash. constexpr auto conversion_scale = static_cast ( std::numeric_limits::digits / std::numeric_limits::digits ); for(auto output_index = static_cast(UINT8_C(0)); #if defined(WIDE_INTEGER_NAMESPACE) output_index < WIDE_INTEGER_NAMESPACE::math::wide_integer::detail::array_detail::tuple_size::value; #else output_index < ::math::wide_integer::detail::array_detail::tuple_size::value; #endif ++output_index) { const auto right_shift_amount = static_cast ( static_cast ( static_cast ( static_cast(conversion_scale - static_cast(UINT8_C(1))) - static_cast(output_index % conversion_scale) ) * static_cast(UINT8_C(8)) ) ); hash_result[output_index] = static_cast ( transform_context[static_cast(output_index / conversion_scale)] >> right_shift_amount ); } return hash_result; } private: std::uint32_t my_datalen { }; // NOLINT(readability-identifier-naming) std::uint64_t my_bitlen { }; // NOLINT(readability-identifier-naming) data_array_type my_data { }; // NOLINT(readability-identifier-naming) transform_context_type transform_context { }; // NOLINT(readability-identifier-naming) constexpr auto sha256_transform() -> void { #if defined(WIDE_INTEGER_NAMESPACE) WIDE_INTEGER_NAMESPACE::math::wide_integer::detail::array_detail::array(UINT8_C(64))> m { }; #else ::math::wide_integer::detail::array_detail::array(UINT8_C(64))> m { }; #endif for(auto i = static_cast(UINT8_C(0)), j = static_cast(UINT8_C(0)); i < static_cast(UINT8_C(16)); ++i, j = static_cast(j + static_cast(UINT8_C(4)))) { m[i] = // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic,cppcoreguidelines-pro-bounds-constant-array-index) static_cast ( static_cast(static_cast(my_data[static_cast(j + static_cast(UINT8_C(0)))]) << static_cast(UINT8_C(24))) // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic,cppcoreguidelines-pro-bounds-constant-array-index) | static_cast(static_cast(my_data[static_cast(j + static_cast(UINT8_C(1)))]) << static_cast(UINT8_C(16))) // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic,cppcoreguidelines-pro-bounds-constant-array-index) | static_cast(static_cast(my_data[static_cast(j + static_cast(UINT8_C(2)))]) << static_cast(UINT8_C( 8))) // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic,cppcoreguidelines-pro-bounds-constant-array-index) | static_cast(static_cast(my_data[static_cast(j + static_cast(UINT8_C(3)))]) << static_cast(UINT8_C( 0))) // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic,cppcoreguidelines-pro-bounds-constant-array-index) ); } for(auto i = static_cast(UINT8_C(16)) ; i < static_cast(UINT8_C(64)); ++i) { m[i] = ssig1(m[i - static_cast(UINT8_C(2))]) + m[i - static_cast(UINT8_C(7))] + ssig0(m[i - static_cast(UINT8_C(15))]) + m[i - static_cast(UINT8_C(16))]; // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic,cppcoreguidelines-pro-bounds-constant-array-index) } #if defined(WIDE_INTEGER_NAMESPACE) constexpr WIDE_INTEGER_NAMESPACE::math::wide_integer::detail::array_detail::array transform_constants = #else constexpr ::math::wide_integer::detail::array_detail::array transform_constants = #endif { static_cast(UINT32_C(0x428A2F98)), static_cast(UINT32_C(0x71374491)), static_cast(UINT32_C(0xB5C0FBCF)), static_cast(UINT32_C(0xE9B5DBA5)), static_cast(UINT32_C(0x3956C25B)), static_cast(UINT32_C(0x59F111F1)), static_cast(UINT32_C(0x923F82A4)), static_cast(UINT32_C(0xAB1C5ED5)), static_cast(UINT32_C(0xD807AA98)), static_cast(UINT32_C(0x12835B01)), static_cast(UINT32_C(0x243185BE)), static_cast(UINT32_C(0x550C7DC3)), static_cast(UINT32_C(0x72BE5D74)), static_cast(UINT32_C(0x80DEB1FE)), static_cast(UINT32_C(0x9BDC06A7)), static_cast(UINT32_C(0xC19BF174)), static_cast(UINT32_C(0xE49B69C1)), static_cast(UINT32_C(0xEFBE4786)), static_cast(UINT32_C(0x0FC19DC6)), static_cast(UINT32_C(0x240CA1CC)), static_cast(UINT32_C(0x2DE92C6F)), static_cast(UINT32_C(0x4A7484AA)), static_cast(UINT32_C(0x5CB0A9DC)), static_cast(UINT32_C(0x76F988DA)), static_cast(UINT32_C(0x983E5152)), static_cast(UINT32_C(0xA831C66D)), static_cast(UINT32_C(0xB00327C8)), static_cast(UINT32_C(0xBF597FC7)), static_cast(UINT32_C(0xC6E00BF3)), static_cast(UINT32_C(0xD5A79147)), static_cast(UINT32_C(0x06CA6351)), static_cast(UINT32_C(0x14292967)), static_cast(UINT32_C(0x27B70A85)), static_cast(UINT32_C(0x2E1B2138)), static_cast(UINT32_C(0x4D2C6DFC)), static_cast(UINT32_C(0x53380D13)), static_cast(UINT32_C(0x650A7354)), static_cast(UINT32_C(0x766A0ABB)), static_cast(UINT32_C(0x81C2C92E)), static_cast(UINT32_C(0x92722C85)), static_cast(UINT32_C(0xA2BFE8A1)), static_cast(UINT32_C(0xA81A664B)), static_cast(UINT32_C(0xC24B8B70)), static_cast(UINT32_C(0xC76C51A3)), static_cast(UINT32_C(0xD192E819)), static_cast(UINT32_C(0xD6990624)), static_cast(UINT32_C(0xF40E3585)), static_cast(UINT32_C(0x106AA070)), static_cast(UINT32_C(0x19A4C116)), static_cast(UINT32_C(0x1E376C08)), static_cast(UINT32_C(0x2748774C)), static_cast(UINT32_C(0x34B0BCB5)), static_cast(UINT32_C(0x391C0CB3)), static_cast(UINT32_C(0x4ED8AA4A)), static_cast(UINT32_C(0x5B9CCA4F)), static_cast(UINT32_C(0x682E6FF3)), static_cast(UINT32_C(0x748F82EE)), static_cast(UINT32_C(0x78A5636F)), static_cast(UINT32_C(0x84C87814)), static_cast(UINT32_C(0x8CC70208)), static_cast(UINT32_C(0x90BEFFFA)), static_cast(UINT32_C(0xA4506CEB)), static_cast(UINT32_C(0xBEF9A3F7)), static_cast(UINT32_C(0xC67178F2)) }; transform_context_type state = transform_context; for(auto i = static_cast(UINT8_C(0)); i < static_cast(UINT8_C(64)); ++i) { const auto tmp1 = static_cast ( state[static_cast(UINT8_C(7))] + bsig1(state[static_cast(UINT8_C(4))]) + ch(state[static_cast(UINT8_C(4))], state[static_cast(UINT8_C(5))], state[static_cast(UINT8_C(6))]) + transform_constants[i] // NOLINT(cppcoreguidelines-pro-bounds-constant-array-index) + m[i] // NOLINT(cppcoreguidelines-pro-bounds-constant-array-index) ); const auto tmp2 = static_cast ( bsig0(state[static_cast(UINT8_C(0))]) + maj(state[static_cast(UINT8_C(0))], state[static_cast(UINT8_C(1))], state[static_cast(UINT8_C(2))]) ); state[static_cast(UINT8_C(7))] = state[static_cast(UINT8_C(6))]; state[static_cast(UINT8_C(6))] = state[static_cast(UINT8_C(5))]; state[static_cast(UINT8_C(5))] = state[static_cast(UINT8_C(4))]; state[static_cast(UINT8_C(4))] = state[static_cast(UINT8_C(3))] + tmp1; state[static_cast(UINT8_C(3))] = state[static_cast(UINT8_C(2))]; state[static_cast(UINT8_C(2))] = state[static_cast(UINT8_C(1))]; state[static_cast(UINT8_C(1))] = state[static_cast(UINT8_C(0))]; state[static_cast(UINT8_C(0))] = static_cast(tmp1 + tmp2); } transform_context[static_cast(UINT8_C(0))] += state[static_cast(UINT8_C(0))]; transform_context[static_cast(UINT8_C(1))] += state[static_cast(UINT8_C(1))]; transform_context[static_cast(UINT8_C(2))] += state[static_cast(UINT8_C(2))]; transform_context[static_cast(UINT8_C(3))] += state[static_cast(UINT8_C(3))]; transform_context[static_cast(UINT8_C(4))] += state[static_cast(UINT8_C(4))]; transform_context[static_cast(UINT8_C(5))] += state[static_cast(UINT8_C(5))]; transform_context[static_cast(UINT8_C(6))] += state[static_cast(UINT8_C(6))]; transform_context[static_cast(UINT8_C(7))] += state[static_cast(UINT8_C(7))]; } static constexpr auto rotl(std::uint32_t a, unsigned b) -> std::uint32_t { return (static_cast(a << b) | static_cast(a >> (static_cast(UINT8_C(32)) - b))); } static constexpr auto rotr(std::uint32_t a, unsigned b) -> std::uint32_t { return (static_cast(a >> b) | static_cast(a << (static_cast(UINT8_C(32)) - b))); } static constexpr auto ch (std::uint32_t x, std::uint32_t y, std::uint32_t z) -> std::uint32_t { return (static_cast(x & y) ^ static_cast(~x & z)); } static constexpr auto maj(std::uint32_t x, std::uint32_t y, std::uint32_t z) -> std::uint32_t { return (static_cast(x & y) ^ static_cast(x & z) ^ static_cast(y & z)); } static constexpr auto bsig0(std::uint32_t x) -> std::uint32_t { return (rotr(x, static_cast(UINT8_C( 2))) ^ rotr(x, static_cast(UINT8_C(13))) ^ rotr(x, static_cast(UINT8_C(22)))); } static constexpr auto bsig1(std::uint32_t x) -> std::uint32_t { return (rotr(x, static_cast(UINT8_C( 6))) ^ rotr(x, static_cast(UINT8_C(11))) ^ rotr(x, static_cast(UINT8_C(25)))); } static constexpr auto ssig0(std::uint32_t x) -> std::uint32_t { return (rotr(x, static_cast(UINT8_C( 7))) ^ rotr(x, static_cast(UINT8_C(18))) ^ (x >> static_cast(UINT8_C( 3)))); } static constexpr auto ssig1(std::uint32_t x) -> std::uint32_t { return (rotr(x, static_cast(UINT8_C(17))) ^ rotr(x, static_cast(UINT8_C(19))) ^ (x >> static_cast(UINT8_C(10)))); } }; template struct ecc_point { #if defined(WIDE_INTEGER_NAMESPACE) using uint_type = WIDE_INTEGER_NAMESPACE::math::wide_integer::uintwide_t(CurveBits), LimbType, void, false>; #else using uint_type = ::math::wide_integer::uintwide_t(CurveBits), LimbType, void, false>; #endif #if defined(WIDE_INTEGER_NAMESPACE) using double_sint_type = WIDE_INTEGER_NAMESPACE::math::wide_integer::uintwide_t(std::numeric_limits::digits * static_cast(INT8_C(2))), LimbType, void, true>; #else using double_sint_type = ::math::wide_integer::uintwide_t(std::numeric_limits::digits * static_cast(INT8_C(2))), LimbType, void, true>; #endif static_assert(static_cast(std::numeric_limits::digits) == CurveBits, "Error: Wrong number of bits in the smallest unsigned type of the point"); using limb_type = typename uint_type::limb_type; using point_type = struct point_type { explicit constexpr point_type(double_sint_type x = static_cast(static_cast(UINT8_C(0))), // NOLINT(google-explicit-constructor,hicpp-explicit-conversions,bugprone-easily-swappable-parameters) double_sint_type y = static_cast(static_cast(UINT8_C(0)))) noexcept : my_x(x), my_y(y) { } // LCOV_EXCL_LINE double_sint_type my_x; // NOLINT(misc-non-private-member-variables-in-classes) double_sint_type my_y; // NOLINT(misc-non-private-member-variables-in-classes) }; }; template struct elliptic_curve : public ecc_point // NOLINT(cppcoreguidelines-pro-bounds-array-to-pointer-decay,hicpp-no-array-decay) { using base_class_type = ecc_point; // NOLINT(cppcoreguidelines-pro-bounds-array-to-pointer-decay,hicpp-no-array-decay) using point_type = typename base_class_type::point_type; using uint_type = typename base_class_type::uint_type; using double_sint_type = typename base_class_type::double_sint_type; using limb_type = typename base_class_type::limb_type; using keypair_type = std::pair>; #if defined(WIDE_INTEGER_NAMESPACE) using quadruple_sint_type = WIDE_INTEGER_NAMESPACE::math::wide_integer::uintwide_t(std::numeric_limits::digits * static_cast(INT8_C(4))), limb_type, void, true>; #else using quadruple_sint_type = ::math::wide_integer::uintwide_t(std::numeric_limits::digits * static_cast(INT8_C(4))), limb_type, void, true>; #endif #if defined(WIDE_INTEGER_NAMESPACE) using sexatuple_sint_type = WIDE_INTEGER_NAMESPACE::math::wide_integer::uintwide_t(std::numeric_limits::digits * static_cast(INT8_C(6))), limb_type, void, true>; #else using sexatuple_sint_type = ::math::wide_integer::uintwide_t(std::numeric_limits::digits * static_cast(INT8_C(6))), limb_type, void, true>; #endif #if defined(WIDE_INTEGER_NAMESPACE) using duodectuple_sint_type = WIDE_INTEGER_NAMESPACE::math::wide_integer::uintwide_t(std::numeric_limits::digits * static_cast(INT8_C(12))), limb_type, void, true>; #else using duodectuple_sint_type = ::math::wide_integer::uintwide_t(std::numeric_limits::digits * static_cast(INT8_C(12))), limb_type, void, true>; #endif static constexpr auto curve_p () noexcept -> double_sint_type { return double_sint_type(FieldCharacteristicP); } // NOLINT(cppcoreguidelines-pro-bounds-array-to-pointer-decay,hicpp-no-array-decay) static constexpr auto curve_a () noexcept -> double_sint_type { return double_sint_type(CurveCoefficientA); } // NOLINT(cppcoreguidelines-pro-bounds-array-to-pointer-decay,hicpp-no-array-decay) static constexpr auto curve_b () noexcept -> double_sint_type { return double_sint_type(CurveCoefficientB); } // NOLINT(cppcoreguidelines-pro-bounds-array-to-pointer-decay,hicpp-no-array-decay) static constexpr auto curve_gx() noexcept -> double_sint_type { return double_sint_type(CoordGx); } // NOLINT(cppcoreguidelines-pro-bounds-array-to-pointer-decay,hicpp-no-array-decay) static constexpr auto curve_gy() noexcept -> double_sint_type { return double_sint_type(CoordGy); } // NOLINT(cppcoreguidelines-pro-bounds-array-to-pointer-decay,hicpp-no-array-decay) static constexpr auto curve_n () noexcept -> double_sint_type { return double_sint_type(SubGroupOrderN); } // NOLINT(cppcoreguidelines-pro-bounds-array-to-pointer-decay,hicpp-no-array-decay) static auto inverse_mod(const double_sint_type& k, const double_sint_type& p) -> double_sint_type // NOLINT(misc-no-recursion) { // Returns the inverse of k modulo p. // This function returns the only integer x such that (x * k) % p == 1. // k must be non-zero and p must be a prime. if(k == 0) { // Error: Division by zero. return 0; // LCOV_EXCL_LINE } if(k < 0) { // k ** -1 = p - (-k) ** -1 (mod p) return p - inverse_mod(-k, p); } // Extended Euclidean algorithm. auto s = double_sint_type(static_cast(UINT8_C(0))); auto old_s = double_sint_type(static_cast(UINT8_C(1))); auto r = p; auto old_r = k; while(r != 0U) // NOLINT(altera-id-dependent-backward-branch) { const auto quotient = divmod(old_r, r).first; const auto tmp_r = r; r = old_r - (quotient * r); old_r = tmp_r; const auto tmp_s = s; s = old_s - (quotient * s); old_s = tmp_s; } return divmod(old_s, p).second; } // Functions that work on curve points static auto is_on_curve(const point_type& point) -> bool { // Returns True if the given point lies on the elliptic curve. if((point.my_x == 0) && (point.my_y == 0)) { // None represents the point at infinity. return true; // LCOV_EXCL_LINE } // Test the condition: // (y * y - x * x * x - curve.a * x -curve.b) % curve.p == 0 const auto num = quadruple_sint_type ( (quadruple_sint_type(point.my_y) * quadruple_sint_type(point.my_y)) - (quadruple_sint_type(point.my_x) * (quadruple_sint_type(point.my_x) * quadruple_sint_type(point.my_x))) - (quadruple_sint_type(point.my_x) * quadruple_sint_type(curve_a())) - quadruple_sint_type(curve_b()) ); const auto divmod_result = divmod(num, quadruple_sint_type(curve_p())).second; return (divmod_result == 0); } // LCOV_EXCL_START static constexpr auto point_neg(const point_type& point) -> point_type { // Returns the negation of the point on the curve (i.e., -point). return { ((point.my_x == 0) && (point.my_y == 0)) ? point_type(0) : point_type { point.my_x, -divmod(point.my_y, curve_p()).second } }; } // LCOV_EXCL_STOP static auto point_add(const point_type& point1, const point_type& point2) -> point_type { // Returns the result of (point1 + point2) according to the group law. const auto& x1 = point1.my_x; const auto& y1 = point1.my_y; const auto& x2 = point2.my_x; const auto& y2 = point2.my_y; if((x1 == 0) && (y1 == 0)) { // 0 + point2 = point2 return point_type(point2); } if((x2 == 0) && (y2 == 0)) { // point1 + 0 = point1 return point_type(point1); // LCOV_EXCL_LINE } if((x1 == x2) && (y1 != y2)) { // Equivalent to: point1 + (-point1) = 0 return point_type { }; // LCOV_EXCL_LINE } // Differentiate the cases (point1 == point2) and (point1 != point2). const auto m = quadruple_sint_type ( (x1 == x2) ? (quadruple_sint_type(x1) * quadruple_sint_type(x1) * 3 + quadruple_sint_type(curve_a())) * quadruple_sint_type(inverse_mod(y1 * 2, curve_p())) : quadruple_sint_type(y1 - y2) * quadruple_sint_type(inverse_mod(x1 - x2, curve_p())) ); const auto x3 = duodectuple_sint_type ( duodectuple_sint_type(m) * duodectuple_sint_type(m) - duodectuple_sint_type(x1 + x2) ); auto y3 = duodectuple_sint_type ( duodectuple_sint_type(y1) + duodectuple_sint_type(m) * (x3 - duodectuple_sint_type(x1)) ); // Negate y3 for the modulus operation below. y3.negate(); return point_type ( double_sint_type(divmod(x3, duodectuple_sint_type(curve_p())).second), double_sint_type(divmod(y3, duodectuple_sint_type(curve_p())).second) ); } static auto scalar_mult(const double_sint_type& k, const point_type& point) -> point_type // NOLINT(misc-no-recursion) { // Returns k * point computed using the double and point_add algorithm. if(((k % curve_n()) == 0) || ((point.my_x == 0) && (point.my_y == 0))) { return point_type { }; // LCOV_EXCL_LINE } if(k < 0) { // k * point = -k * (-point) return scalar_mult(-k, point_neg(point)); // LCOV_EXCL_LINE } point_type result { }; point_type addend = point; double_sint_type k_val(k); while(k_val != 0) // NOLINT(altera-id-dependent-backward-branch) { const auto lo_bit = static_cast ( static_cast(k_val) & static_cast(UINT8_C(1)) ); if(lo_bit != static_cast(UINT8_C(0))) { // Add. result = point_add(result, addend); } // Double. addend = point_add(addend, addend); k_val >>= static_cast(UINT8_C(1)); } return result; } template static auto get_pseudo_random_uint(const UnknownWideUintType& a = (std::numeric_limits::min)(), const UnknownWideUintType& b = (std::numeric_limits::max)()) -> UnknownWideUintType { using local_wide_unsigned_integer_type = UnknownWideUintType; #if defined(WIDE_INTEGER_NAMESPACE) using local_distribution_type = WIDE_INTEGER_NAMESPACE::math::wide_integer::uniform_int_distribution; #else using local_distribution_type = ::math::wide_integer::uniform_int_distribution; #endif using local_random_engine_type = std::linear_congruential_engine; using local_random_device_type = std::random_device; local_random_device_type dev; const auto seed_value = static_cast(dev()); local_random_engine_type generator(seed_value); local_distribution_type dist { a, b }; const auto unsigned_pseudo_random_value = dist(generator); return unsigned_pseudo_random_value; } static auto make_keypair(const uint_type* p_uint_seed = nullptr) -> keypair_type { // This subroutine generate a random private-public key pair. // The input parameter p_uint_seed can, however, be used to // provide a fixed-input value for the private key. // Also be sure to limit to random.randrange(1, curve.n). const auto private_key = uint_type ( (p_uint_seed == nullptr) ? get_pseudo_random_uint(uint_type { static_cast(UINT8_C(1)) }, curve_n()) : *p_uint_seed ); const auto public_key = scalar_mult(private_key, point_type(curve_gx(), curve_gy())); return { private_key, { uint_type { public_key.my_x }, uint_type { public_key.my_y } } }; } template static auto hash_message(MsgIteratorType msg_first, MsgIteratorType msg_last) -> uint_type { // This subroutine returns the hash of the message (msg), where // the type of the hash is 256-bit SHA2, as implenebted locally above. // For those interested in the general case of ECC, a larger/smaller // bit-length hash needs to be left/right shifted for cases when there // are different hash/curve bit-lengths (as specified in FIPS 180). const auto message { std::vector(msg_first, msg_last) }; using hash_type = hash_sha256; hash_type hash_object; const auto hash_result = hash_object.hash(message.data(), message.size()); const auto z = [&hash_result]() { auto u = uint_type { }; static_cast(import_bits(u, hash_result.cbegin(), hash_result.cend())); return u; }(); return z; } template static auto sign_message(const uint_type& private_key, MsgIteratorType msg_first, MsgIteratorType msg_last, const uint_type* p_uint_seed = nullptr) -> std::pair { const auto z = sexatuple_sint_type(hash_message(msg_first, msg_last)); double_sint_type r { }; double_sint_type s { }; const auto n = sexatuple_sint_type(curve_n()); const auto pk = sexatuple_sint_type(private_key); while((r == 0) || (s == 0)) // NOLINT(altera-id-dependent-backward-branch) { const uint_type uk { (p_uint_seed == nullptr) ? std::move(get_pseudo_random_uint()) : *p_uint_seed }; const double_sint_type k { uk }; const point_type pt(scalar_mult(k, point_type(curve_gx(), curve_gy()))); r = divmod(pt.my_x, curve_n()).second; const sexatuple_sint_type num { (sexatuple_sint_type(z) + (sexatuple_sint_type(r) * pk)) * sexatuple_sint_type(inverse_mod(k, curve_n())) }; s = double_sint_type { divmod(num, n).second }; } return { uint_type(r), uint_type(s) }; } template static auto verify_signature(const std::pair& pub, MsgIteratorType msg_first, MsgIteratorType msg_last, const std::pair& sig) -> bool { const sexatuple_sint_type w(inverse_mod(sig.second, curve_n())); const sexatuple_sint_type n(curve_n()); const auto z = hash_message(msg_first, msg_last); const double_sint_type u1(divmod(sexatuple_sint_type(z) * w, n).second); const double_sint_type u2(divmod(sexatuple_sint_type(sig.first) * w, n).second); const auto pt = point_add ( scalar_mult(u1,point_type(curve_gx(), curve_gy())), scalar_mult(u2,point_type(pub.first, pub.second)) ); return ( divmod(double_sint_type(sig.first), curve_n()).second == divmod(pt.my_x, curve_n()).second ); } }; constexpr char CurveName [] = "secp256k1"; // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,cppcoreguidelines-pro-bounds-array-to-pointer-decay,modernize-avoid-c-arrays) constexpr char FieldCharacteristicP[] = "0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F"; // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,cppcoreguidelines-pro-bounds-array-to-pointer-decay,modernize-avoid-c-arrays) constexpr char CurveCoefficientA [] = "0x0"; // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,cppcoreguidelines-pro-bounds-array-to-pointer-decay,modernize-avoid-c-arrays) constexpr char CurveCoefficientB [] = "0x7"; // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,cppcoreguidelines-pro-bounds-array-to-pointer-decay,modernize-avoid-c-arrays) constexpr char BasePointGx [] = "0x79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798"; // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,cppcoreguidelines-pro-bounds-array-to-pointer-decay,modernize-avoid-c-arrays) constexpr char BasePointGy [] = "0x483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8"; // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,cppcoreguidelines-pro-bounds-array-to-pointer-decay,modernize-avoid-c-arrays) constexpr char SubGroupOrderN [] = "0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141"; // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,cppcoreguidelines-pro-bounds-array-to-pointer-decay,modernize-avoid-c-arrays) constexpr auto SubGroupCoFactorH = static_cast(INT8_C(1)); } // namespace example013_ecdsa #if defined(WIDE_INTEGER_NAMESPACE) auto WIDE_INTEGER_NAMESPACE::math::wide_integer::example013_ecdsa_sign_verify() -> bool #else auto ::math::wide_integer::example013_ecdsa_sign_verify() -> bool #endif { auto result_is_ok = true; using elliptic_curve_type = example013_ecdsa::elliptic_curve(UINT16_C(256)), std::uint32_t, example013_ecdsa::CurveName, // NOLINT(cppcoreguidelines-pro-bounds-array-to-pointer-decay,hicpp-no-array-decay) example013_ecdsa::FieldCharacteristicP, // NOLINT(cppcoreguidelines-pro-bounds-array-to-pointer-decay,hicpp-no-array-decay) example013_ecdsa::CurveCoefficientA, // NOLINT(cppcoreguidelines-pro-bounds-array-to-pointer-decay,hicpp-no-array-decay) example013_ecdsa::CurveCoefficientB, // NOLINT(cppcoreguidelines-pro-bounds-array-to-pointer-decay,hicpp-no-array-decay) example013_ecdsa::BasePointGx, // NOLINT(cppcoreguidelines-pro-bounds-array-to-pointer-decay,hicpp-no-array-decay) example013_ecdsa::BasePointGy, // NOLINT(cppcoreguidelines-pro-bounds-array-to-pointer-decay,hicpp-no-array-decay) example013_ecdsa::SubGroupOrderN, // NOLINT(cppcoreguidelines-pro-bounds-array-to-pointer-decay,hicpp-no-array-decay) example013_ecdsa::SubGroupCoFactorH>; static_assert(elliptic_curve_type::curve_p() == elliptic_curve_type::double_sint_type(example013_ecdsa::FieldCharacteristicP), // NOLINT(cppcoreguidelines-pro-bounds-array-to-pointer-decay,hicpp-no-array-decay) "Error: Elliptic curve Field Characteristic p seems to be incorrect"); static_assert(elliptic_curve_type::curve_a() == elliptic_curve_type::double_sint_type(example013_ecdsa::CurveCoefficientA), // NOLINT(cppcoreguidelines-pro-bounds-array-to-pointer-decay,hicpp-no-array-decay) "Error: Elliptic curve curve coefficient a seems to be incorrect"); static_assert(elliptic_curve_type::curve_b() == elliptic_curve_type::double_sint_type(example013_ecdsa::CurveCoefficientB), // NOLINT(cppcoreguidelines-pro-bounds-array-to-pointer-decay,hicpp-no-array-decay) "Error: Elliptic curve curve coefficient b seems to be incorrect"); static_assert(elliptic_curve_type::curve_gx() == elliptic_curve_type::double_sint_type(example013_ecdsa::BasePointGx), // NOLINT(cppcoreguidelines-pro-bounds-array-to-pointer-decay,hicpp-no-array-decay) "Error: Elliptic curve base-point Gx seems to be incorrect"); static_assert(elliptic_curve_type::curve_gy() == elliptic_curve_type::double_sint_type(example013_ecdsa::BasePointGy), // NOLINT(cppcoreguidelines-pro-bounds-array-to-pointer-decay,hicpp-no-array-decay) "Error: Elliptic curve base-point Gx seems to be incorrect"); static_assert(elliptic_curve_type::curve_n() == elliptic_curve_type::double_sint_type(example013_ecdsa::SubGroupOrderN), // NOLINT(cppcoreguidelines-pro-bounds-array-to-pointer-decay,hicpp-no-array-decay) "Error: Elliptic curve Sub-Group Order seems to be incorrect"); // Declare the message "Hello!" as an array of chars. #if defined(WIDE_INTEGER_NAMESPACE) constexpr WIDE_INTEGER_NAMESPACE::math::wide_integer::detail::array_detail::array(UINT8_C(6))> msg_as_array { 'H', 'e', 'l', 'l', 'o', '!' }; #else constexpr ::math::wide_integer::detail::array_detail::array(UINT8_C(6))> msg_as_array { 'H', 'e', 'l', 'l', 'o', '!' }; #endif // Get the message to sign as a string and ensure that it is "Hello!". const auto msg_as_string = std::string(msg_as_array.cbegin(), msg_as_array.cend()); const auto result_msg_as_string_is_ok = (msg_as_string == "Hello!"); result_is_ok = (result_msg_as_string_is_ok && result_is_ok); { // Test the hash SHA-2 HASH-256 implementation. const auto hash_result = elliptic_curve_type::hash_message(msg_as_array.cbegin(), msg_as_array.cend()); const auto result_hash_is_ok = ( hash_result == elliptic_curve_type::uint_type("0x334D016F755CD6DC58C53A86E183882F8EC14F52FB05345887C8A5EDD42C87B7") ); result_is_ok = (result_hash_is_ok && result_is_ok); } { // Test ECC key generation, sign and verify. In this case we use random (but pre-defined seeds // for both keygen as well as signing. const auto seed_keygen = elliptic_curve_type::uint_type("0xC6455BF2F380F6B81F5FD1A1DBC2392B3783ED1E7D91B62942706E5584BA0B92"); const auto keypair = elliptic_curve_type::make_keypair(&seed_keygen); using local_point_type = typename elliptic_curve_type::point_type; const auto result_is_on_curve_is_ok = elliptic_curve_type::is_on_curve ( local_point_type { std::get<1>(keypair).first, std::get<1>(keypair).second } ); const auto result_private_is_ok = (std::get<0>(keypair) == "0xC6455BF2F380F6B81F5FD1A1DBC2392B3783ED1E7D91B62942706E5584BA0B92"); const auto result_public_x_is_ok = (std::get<1>(keypair).first == "0xC6235629F157690E1DF37248256C4FB7EFF073D0250F5BD85DF40B9E127A8461"); const auto result_public_y_is_ok = (std::get<1>(keypair).second == "0xCBAA679F07F9B98F915C1FB7D85A379D0559A9EEE6735B1BE0CE0E2E2B2E94DE"); const auto result_keygen_is_ok = ( result_private_is_ok && result_public_x_is_ok && result_public_y_is_ok ); result_is_ok = (result_is_on_curve_is_ok && result_keygen_is_ok && result_is_ok); const auto priv = elliptic_curve_type::uint_type("0x6F73D8E95D6DDBF0EB352A9F0B2CE91931511EDAF9AC8F128D5A4F877C4F0450"); const auto sig = elliptic_curve_type::sign_message(std::get<0>(keypair), msg_as_string.cbegin(), msg_as_string.cend(), &priv); const auto result_sig_is_ok = ( sig == std::make_pair ( elliptic_curve_type::uint_type("0x65717A860F315A21E6E23CDE411C8940DE42A69D8AB26C2465902BE8F3B75E7B"), elliptic_curve_type::uint_type("0xDB8B8E75A7B0C2F0D9EB8DBF1B5236EDEB89B2116F5AEBD40E770F8CCC3D6605") ) ); result_is_ok = (result_sig_is_ok && result_is_ok); const auto result_verify_is_ok = elliptic_curve_type::verify_signature ( std::get<1>(keypair), msg_as_string.cbegin(), msg_as_string.cend(), sig ); result_is_ok = (result_verify_is_ok && result_is_ok); } { // We will now test 3 more successful keygen, sign, verify sequences. for(auto count = static_cast(UINT8_C(0)); count < static_cast(UINT8_C(3)); ++count) { const auto keypair = elliptic_curve_type::make_keypair(); const auto msg_str_append_index = msg_as_string + std::to_string(count); const auto sig = elliptic_curve_type::sign_message ( std::get<0>(keypair), msg_str_append_index.cbegin(), msg_str_append_index.cend() ); const auto result_verify_is_ok = elliptic_curve_type::verify_signature ( std::get<1>(keypair), msg_str_append_index.cbegin(), msg_str_append_index.cend(), sig ); result_is_ok = (result_verify_is_ok && result_is_ok); } } { // We will now test keygen, sign, and a (failing!) verify sequence, // where the message being verified has been artificially modified // and signature verification is expected to fail. const auto keypair = elliptic_curve_type::make_keypair(); const auto sig = elliptic_curve_type::sign_message(std::get<0>(keypair), msg_as_string.cbegin(), msg_as_string.cend()); const auto msg_str_to_fail = msg_as_string + "x"; const auto result_verify_expected_fail_is_ok = (!elliptic_curve_type::verify_signature(std::get<1>(keypair), msg_str_to_fail.cbegin(), msg_str_to_fail.cend(), sig)); result_is_ok = (result_verify_expected_fail_is_ok && result_is_ok); } return result_is_ok; } // Enable this if you would like to activate this main() as a standalone example. #if defined(WIDE_INTEGER_STANDALONE_EXAMPLE013_ECDSA_SIGN_VERIFY) #include #include auto main() -> int { #if defined(WIDE_INTEGER_NAMESPACE) const auto result_is_ok = WIDE_INTEGER_NAMESPACE::math::wide_integer::example013_ecdsa_sign_verify(); #else const auto result_is_ok = ::math::wide_integer::example013_ecdsa_sign_verify(); #endif std::cout << "result_is_ok: " << std::boolalpha << result_is_ok << std::endl; return (result_is_ok ? 0 : -1); } #endif ================================================ FILE: examples/example014_pi_spigot_wide.cpp ================================================ /////////////////////////////////////////////////////////////////// // Copyright Christopher Kormanyos 2023 - 2025. // // Distributed under the Boost Software License, // // Version 1.0. (See accompanying file LICENSE_1_0.txt // // or copy at http://www.boost.org/LICENSE_1_0.txt) // /////////////////////////////////////////////////////////////////// #include #include #include #include #include #include #include #include namespace example014_pi_spigot { template class pi_spigot { private: using unsigned_small_type = UnsignedSmallType; using unsigned_large_type = UnsignedLargeType; static constexpr auto result_digit() noexcept -> std::uint32_t { return ResultDigit; } static constexpr auto loop_digit () noexcept -> std::uint32_t { return LoopDigit; } static_assert(result_digit() <= static_cast(UINT16_C(10011)), "Error: result_digit exceeds its limit of 10,011"); static_assert(std::numeric_limits::digits * 2 == std::numeric_limits::digits, "Error: unsigned_large_type must be exactly twice as wide as unsigned_small_type"); static_assert((!std::numeric_limits::is_signed), "Error: unsigned_small_type must be unsigned"); static_assert((!std::numeric_limits::is_signed), "Error: unsigned_large_type must be unsigned"); static constexpr auto input_scale(std::uint32_t x) noexcept -> std::uint32_t { return static_cast ( static_cast ( x * static_cast ( static_cast(static_cast(UINT8_C(10) * loop_digit()) / static_cast(UINT8_C(3))) + static_cast(UINT8_C(1)) ) ) / loop_digit() ); } public: static constexpr auto get_output_static_size() noexcept -> std::uint32_t { return result_digit(); } static constexpr auto get_input_static_size() noexcept -> std::uint32_t { return input_scale(get_output_static_size()); } using input_container_type = std::vector; using output_value_type = std::uint8_t; pi_spigot() { if(my_pi_in.empty()) { constexpr auto input_size = static_cast(get_input_static_size()); my_pi_in.resize(input_size); } } pi_spigot(const pi_spigot&) = delete; pi_spigot(pi_spigot&&) = delete; ~pi_spigot() = default; // LCOV_EXCL_LINE auto operator=(const pi_spigot&) -> pi_spigot& = delete; auto operator=(pi_spigot&&) noexcept -> pi_spigot& = delete; WIDE_INTEGER_NODISCARD auto get_operation_count() const noexcept -> std::uintmax_t { return my_operation_count; } template auto calculate(OutputIteratorType output_first) -> void { // Use pi_spigot::calculate() to calculate result_digit // decimal digits of pi. // The caller is responsible for providing the output memory // for the result of pi. // The input memory used for internal calculation details // is managed by the pi_spigot class itself. std::fill(my_pi_in.begin(), my_pi_in.end(), static_cast(UINT8_C(0))); auto val_c = static_cast(static_cast(UINT8_C(0))); my_output_count = static_cast(UINT8_C(0)); my_operation_count = static_cast(UINT8_C(0)); const auto local_pow10 = static_cast(pow10(loop_digit())); // Operation count Mathematica(R), example for loop_digit=9. // Sum[Floor[((d - j) (Floor[((10 9)/3)] + 1))/9], {j, 0, Floor[d/9] 9, 9}] for(auto j = static_cast(UINT8_C(0)); j < result_digit(); // NOLINT(altera-id-dependent-backward-branch) j = static_cast(j + loop_digit())) { auto val_d = static_cast(UINT8_C(0)); const auto ilim = input_scale(result_digit() - j); for(auto i = static_cast(INT8_C(0)); i < ilim; // NOLINT(altera-id-dependent-backward-branch) ++i) { const auto my_index = static_cast ( static_cast(ilim - static_cast(UINT8_C(1))) - i ); unsigned_large_type di { my_pi_in[my_index] }; if(j == static_cast(UINT8_C(0))) { di = std::move(static_cast(d_init())); } val_d += (di * local_pow10); const auto val_b = static_cast ( static_cast ( my_index * static_cast(UINT8_C(2)) ) + static_cast(UINT8_C(1)) ); my_pi_in[my_index] = static_cast(val_d % val_b); val_d /= val_b; if(my_index > static_cast(UINT8_C(1))) { val_d *= my_index; } ++my_operation_count; } // Parse the next digits of pi, where the group has loop_digit digits. // If loop_digit is 4, for instance, then successive groups // of digits have a form such as: 3141, 5926, ..., etc. const auto next_digits = static_cast ( val_c + static_cast(val_d / local_pow10) ); val_c = static_cast(val_d % local_pow10); const auto n = (std::min) ( loop_digit(), static_cast(result_digit() - j) ); auto scale10 = pow10(loop_digit() - UINT32_C(1)); for(auto i = static_cast(UINT8_C(0)); i < static_cast(n); ++i) // NOLINT(altera-id-dependent-backward-branch) { using local_diff_type = typename std::iterator_traits::difference_type; const auto out_index = static_cast ( static_cast(static_cast(j) + i) ); output_first[out_index] = static_cast ( static_cast(static_cast(next_digits / scale10) % UINT32_C(10)) ); scale10 = static_cast(scale10 / UINT32_C(10)); } my_output_count += n; } } private: static input_container_type my_pi_in; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables) std::uintmax_t my_operation_count { }; // NOLINT(readability-identifier-naming) std::uint32_t my_output_count { }; // NOLINT(readability-identifier-naming) static auto pow10(std::uint32_t n) -> unsigned_small_type // NOLINT(misc-no-recursion) { return ( (n == static_cast(UINT8_C(0))) ? static_cast(UINT32_C(1)) : static_cast(pow10(n - static_cast(UINT8_C(1))) * UINT32_C(10)) ); } static auto d_init() -> unsigned_small_type { return static_cast ( pow10(loop_digit()) / static_cast(UINT8_C(5)) ); } }; template typename pi_spigot::input_container_type pi_spigot::my_pi_in { }; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables,hicpp-uppercase-literal-suffix,readability-uppercase-literal-suffix) const std::array(UINT8_C(12))> pi_control_data = { "3", "1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679821480865132823066470938446095505822317253594081284811174502841027019385211055596446229489549303819644288109756659334461284756482337867831652712019091456485669234603486104543266482133936072602491412737245870066063155881748815209209628292540917153643678925903600113305305488204665213841469519415116094330572703657595919530921861173819326117931051185480744623799627495673518857527248912279381830119491298336733624406566430860213949463952247371907021798609437027705392171762931767523846748184676694051320005681271452635608277857713427577896091736371787214684409012249534301465495853710507922796892589235420199561121290219608640344181598136297747713099605187072113499999983729780499510597317328160963185950244594553469083026425223082533446850352619311881710100031378387528865875332083814206171776691473035982534904287554687311595628638823537875937519577818577805321712268066130019278766111959092164201989", "3809525720106548586327886593615338182796823030195203530185296899577362259941389124972177528347913151557485724245415069595082953311686172785588907509838175463746493931925506040092770167113900984882401285836160356370766010471018194295559619894676783744944825537977472684710404753464620804668425906949129331367702898915210475216205696602405803815019351125338243003558764024749647326391419927260426992279678235478163600934172164121992458631503028618297455570674983850549458858692699569092721079750930295532116534498720275596023648066549911988183479775356636980742654252786255181841757467289097777279380008164706001614524919217321721477235014144197356854816136115735255213347574184946843852332390739414333454776241686251898356948556209921922218427255025425688767179049460165346680498862723279178608578438382796797668145410095388378636095068006422512520511739298489608412848862694560424196528502221066118630674427862203919494504712371378696095636437191728746776465757396241389086583264599581339047802759009", "9465764078951269468398352595709825822620522489407726719478268482601476990902640136394437455305068203496252451749399651431429809190659250937221696461515709858387410597885959772975498930161753928468138268683868942774155991855925245953959431049972524680845987273644695848653836736222626099124608051243884390451244136549762780797715691435997700129616089441694868555848406353422072225828488648158456028506016842739452267467678895252138522549954666727823986456596116354886230577456498035593634568174324112515076069479451096596094025228879710893145669136867228748940560101503308617928680920874760917824938589009714909675985261365549781893129784821682998948722658804857564014270477555132379641451523746234364542858444795265867821051141354735739523113427166102135969536231442952484937187110145765403590279934403742007310578539062198387447808478489683321445713868751943506430218453191048481005370614680674919278191197939952061419663428754440643745123718192179998391015919561814675142691239748940907186494231961", "5679452080951465502252316038819301420937621378559566389377870830390697920773467221825625996615014215030680384477345492026054146659252014974428507325186660021324340881907104863317346496514539057962685610055081066587969981635747363840525714591028970641401109712062804390397595156771577004203378699360072305587631763594218731251471205329281918261861258673215791984148488291644706095752706957220917567116722910981690915280173506712748583222871835209353965725121083579151369882091444210067510334671103141267111369908658516398315019701651511685171437657618351556508849099898599823873455283316355076479185358932261854896321329330898570642046752590709154814165498594616371802709819943099244889575712828905923233260972997120844335732654893823911932597463667305836041428138830320382490375898524374417029132765618093773444030707469211201913020330380197621101100449293215160842444859637669838952286847831235526582131449576857262433441893039686426243410773226978028073189154411010446823252716201052652272111660396", "6655730925471105578537634668206531098965269186205647693125705863566201855810072936065987648611791045334885034611365768675324944166803962657978771855608455296541266540853061434443185867697514566140680070023787765913440171274947042056223053899456131407112700040785473326993908145466464588079727082668306343285878569830523580893306575740679545716377525420211495576158140025012622859413021647155097925923099079654737612551765675135751782966645477917450112996148903046399471329621073404375189573596145890193897131117904297828564750320319869151402870808599048010941214722131794764777262241425485454033215718530614228813758504306332175182979866223717215916077166925474873898665494945011465406284336639379003976926567214638530673609657120918076383271664162748888007869256029022847210403172118608204190004229661711963779213375751149595015660496318629472654736425230817703675159067350235072835405670403867435136222247715891504953098444893330963408780769325993978054193414473774418426312986080998886874132604721", "5695162396586457302163159819319516735381297416772947867242292465436680098067692823828068996400482435403701416314965897940924323789690706977942236250822168895738379862300159377647165122893578601588161755782973523344604281512627203734314653197777416031990665541876397929334419521541341899485444734567383162499341913181480927777103863877343177207545654532207770921201905166096280490926360197598828161332316663652861932668633606273567630354477628035045077723554710585954870279081435624014517180624643626794561275318134078330336254232783944975382437205835311477119926063813346776879695970309833913077109870408591337464144282277263465947047458784778720192771528073176790770715721344473060570073349243693113835049316312840425121925651798069411352801314701304781643788518529092854520116583934196562134914341595625865865570552690496520985803385072242648293972858478316305777756068887644624824685792603953527734803048029005876075825104747091643961362676044925627420420832085661190625454337213153595845068772460", "2901618766795240616342522577195429162991930645537799140373404328752628889639958794757291746426357455254079091451357111369410911939325191076020825202618798531887705842972591677813149699009019211697173727847684726860849003377024242916513005005168323364350389517029893922334517220138128069650117844087451960121228599371623130171144484640903890644954440061986907548516026327505298349187407866808818338510228334508504860825039302133219715518430635455007668282949304137765527939751754613953984683393638304746119966538581538420568533862186725233402830871123282789212507712629463229563989898935821167456270102183564622013496715188190973038119800497340723961036854066431939509790190699639552453005450580685501956730229219139339185680344903982059551002263535361920419947455385938102343955449597783779023742161727111723643435439478221818528624085140066604433258885698670543154706965747458550332323342107301545940516553790686627333799585115625784322988273723198987571415957811196358330059408730681216028764962867", "4460477464915995054973742562690104903778198683593814657412680492564879855614537234786733039046883834363465537949864192705638729317487233208376011230299113679386270894387993620162951541337142489283072201269014754668476535761647737946752004907571555278196536213239264061601363581559074220202031872776052772190055614842555187925303435139844253223415762336106425063904975008656271095359194658975141310348227693062474353632569160781547818115284366795706110861533150445212747392454494542368288606134084148637767009612071512491404302725386076482363414334623518975766452164137679690314950191085759844239198629164219399490723623464684411739403265918404437805133389452574239950829659122850855582157250310712570126683024029295252201187267675622041542051618416348475651699981161410100299607838690929160302884002691041407928862150784245167090870006992821206604183718065355672525325675328612910424877618258297651579598470356222629348600341587229805349896502262917487882027342092222453398562647669149055628425039127", "5771028402799806636582548892648802545661017296702664076559042909945681506526530537182941270336931378517860904070866711496558343434769338578171138645587367812301458768712660348913909562009939361031029161615288138437909904231747336394804575931493140529763475748119356709110137751721008031559024853090669203767192203322909433467685142214477379393751703443661991040337511173547191855046449026365512816228824462575916333039107225383742182140883508657391771509682887478265699599574490661758344137522397096834080053559849175417381883999446974867626551658276584835884531427756879002909517028352971634456212964043523117600665101241200659755851276178583829204197484423608007193045761893234922927965019875187212726750798125547095890455635792122103334669749923563025494780249011419521238281530911407907386025152274299581807247162591668545133312394804947079119153267343028244186041426363954800044800267049624820179289647669758318327131425170296923488962766844032326092752496035799646925650493681836090032380929345", "9588970695365349406034021665443755890045632882250545255640564482465151875471196218443965825337543885690941130315095261793780029741207665147939425902989695946995565761218656196733786236256125216320862869222103274889218654364802296780705765615144632046927906821207388377814233562823608963208068222468012248261177185896381409183903673672220888321513755600372798394004152970028783076670944474560134556417254370906979396122571429894671543578468788614445812314593571984922528471605049221242470141214780573455105008019086996033027634787081081754501193071412233908663938339529425786905076431006383519834389341596131854347546495569781038293097164651438407007073604112373599843452251610507027056235266012764848308407611830130527932054274628654036036745328651057065874882256981579367897669742205750596834408697350201410206723585020072452256326513410559240190274216248439140359989535394590944070469120914093870012645600162374288021092764579310657922955249887275846101264836999892256959688159205600101655256375678", "5667227966198857827948488558343975187445455129656344348039664205579829368043522027709842942325330225763418070394769941597915945300697521482933665556615678736400536665641654732170439035213295435291694145990416087532018683793702348886894791510716378529023452924407736594956305100742108714261349745956151384987137570471017879573104229690666702144986374645952808243694457897723300487647652413390759204340196340391147320233807150952220106825634274716460243354400515212669324934196739770415956837535551667302739007497297363549645332888698440611964961627734495182736955882207573551766515898551909866653935494810688732068599075407923424023009259007017319603622547564789406475483466477604114632339056513433068449539790709030234604614709616968868850140834704054607429586991382966824681857103188790652870366508324319744047718556789348230894310682870272280973624809399627060747264553992539944280811373694338872940630792615959954626246297070625948455690347119729964090894180595343932512362355081349490043642785271", }; inline auto pi_control_string() -> std::string { auto str = std::string { }; for(auto pstr : pi_control_data) // NOLINT(llvm-qualified-auto,readability-qualified-auto) { str.insert(str.length(), pstr); // LCOV_EXCL_LINE } return str; } } // namespace example014_pi_spigot #if defined(WIDE_INTEGER_NAMESPACE) auto WIDE_INTEGER_NAMESPACE::math::wide_integer::example014_pi_spigot_wide() -> bool #else auto ::math::wide_integer::example014_pi_spigot_wide() -> bool #endif { #if defined(WIDE_INTEGER_NAMESPACE) using unsigned_small_type = WIDE_INTEGER_NAMESPACE::math::wide_integer::uint256_t; using unsigned_large_type = WIDE_INTEGER_NAMESPACE::math::wide_integer::uint512_t; #else using unsigned_small_type = ::math::wide_integer::uint256_t; using unsigned_large_type = ::math::wide_integer::uint512_t; #endif using pi_spigot_type = example014_pi_spigot::pi_spigot(UINT16_C(10001)), static_cast(std::numeric_limits::digits10), unsigned_small_type, unsigned_large_type>; using output_container_type = std::vector; output_container_type pi_out(pi_spigot_type::get_output_static_size()); pi_spigot_type().calculate(pi_out.begin()); const auto result_is_ok = std::equal(pi_out.cbegin(), pi_out.cend(), example014_pi_spigot::pi_control_string().cbegin(), [](const std::uint8_t& by, const char& c) { const auto by_val_to_check = static_cast ( static_cast(c) - static_cast(UINT8_C(0x30)) ); return (by == by_val_to_check); }); return result_is_ok; } // Enable this if you would like to activate this main() as a standalone example. #if defined(WIDE_INTEGER_STANDALONE_EXAMPLE014_PI_SPIGOT_WIDE) #include #include auto main() -> int { #if defined(WIDE_INTEGER_NAMESPACE) const auto result_is_ok = WIDE_INTEGER_NAMESPACE::math::wide_integer::example011_pi_spigot_wide(); #else const auto result_is_ok = ::math::wide_integer::example011_pi_spigot_wide(); #endif std::cout << "result_is_ok: " << std::boolalpha << result_is_ok << std::endl; return (result_is_ok ? 0 : -1); } #endif ================================================ FILE: examples/example_uintwide_t.h ================================================ /////////////////////////////////////////////////////////////////// // Copyright Christopher Kormanyos 2021 - 2026. // // Distributed under the Boost Software License, // // Version 1.0. (See accompanying file LICENSE_1_0.txt // // or copy at http://www.boost.org/LICENSE_1_0.txt) // /////////////////////////////////////////////////////////////////// #ifndef EXAMPLE_UINTWIDE_T_2021_04_29_H // NOLINT(llvm-header-guard) #define EXAMPLE_UINTWIDE_T_2021_04_29_H // This file contains function prototypes of the uintwide_t examples. #include WIDE_INTEGER_NAMESPACE_BEGIN #if(__cplusplus >= 201703L) namespace math::wide_integer { #else namespace math { namespace wide_integer { // NOLINT(modernize-concat-nested-namespaces) #endif auto example000_numeric_limits () -> bool; auto example000a_builtin_convert () -> bool; auto example001_mul_div () -> bool; auto example001a_div_mod () -> bool; auto example002_shl_shr () -> bool; auto example003_sqrt () -> bool; auto example003a_cbrt () -> bool; auto example004_rootk_pow () -> bool; auto example005_powm () -> bool; auto example005a_pow_factors_of_p99 () -> bool; auto example006_gcd () -> bool; auto example007_random_generator () -> bool; auto example008_miller_rabin_prime () -> bool; auto example008a_miller_rabin_prime () -> bool; auto example008b_solovay_strassen_prime () -> bool; auto example009_timed_mul () -> bool; auto example009a_timed_mul_4_by_4 () -> bool; auto example009b_timed_mul_8_by_8 () -> bool; auto example010_uint48_t () -> bool; auto example011_uint24_t () -> bool; auto example012_rsa_crypto () -> bool; auto example013_ecdsa_sign_verify () -> bool; auto example014_pi_spigot_wide () -> bool; #if(__cplusplus >= 201703L) } // namespace math::wide_integer #else } // namespace wide_integer } // namespace math #endif WIDE_INTEGER_NAMESPACE_END #endif // EXAMPLE_UINTWIDE_T_2021_04_29_H ================================================ FILE: math/wide_integer/cpp.hint ================================================ #define __cplusplus 201703L #define WIDE_INTEGER_NUM_LIMITS_CLASS_TYPE class #define WIDE_INTEGER_NAMESPACE ckormanyos #if defined(WIDE_INTEGER_NAMESPACE) #define WIDE_INTEGER_NAMESPACE_BEGIN namespace WIDE_INTEGER_NAMESPACE { #define WIDE_INTEGER_NAMESPACE_END } #else #define WIDE_INTEGER_NAMESPACE_BEGIN #define WIDE_INTEGER_NAMESPACE_END #endif #define WIDE_INTEGER_NODISCARD [[nodiscard]] #define UINT8_C(x) (x) ================================================ FILE: math/wide_integer/uintwide_t.h ================================================ /////////////////////////////////////////////////////////////////// // Copyright Christopher Kormanyos 1999 - 2026. // // Distributed under the Boost Software License, // // Version 1.0. (See accompanying file LICENSE_1_0.txt // // or copy at http://www.boost.org/LICENSE_1_0.txt) // /////////////////////////////////////////////////////////////////// #ifndef UINTWIDE_T_2018_10_02_H // NOLINT(llvm-header-guard) #define UINTWIDE_T_2018_10_02_H #if ((__cplusplus < 202002L) || (defined(__GNUC__) && defined(__AVR__))) #include #else #include #endif #if (defined(__cpp_lib_to_chars) && (__cpp_lib_to_chars >= 201611L)) #include #endif #include #if !defined(WIDE_INTEGER_DISABLE_FLOAT_INTEROP) #include #endif #include #include #include #include #include #if !defined(WIDE_INTEGER_DISABLE_IOSTREAM) #include #include #endif #include #if !defined(WIDE_INTEGER_DISABLE_IMPLEMENT_UTIL_DYNAMIC_ARRAY) #include #endif #if (defined(__cpp_lib_gcd_lcm) && (__cpp_lib_gcd_lcm >= 201606L)) #include #endif #if !defined(WIDE_INTEGER_DISABLE_IOSTREAM) #include #include #endif #if !defined(WIDE_INTEGER_DISABLE_TO_STRING) #include #endif #include #include #if (defined(__clang__) && (__clang_major__ <= 9)) #define WIDE_INTEGER_NUM_LIMITS_CLASS_TYPE struct // NOLINT(cppcoreguidelines-macro-usage) #else #define WIDE_INTEGER_NUM_LIMITS_CLASS_TYPE class // NOLINT(cppcoreguidelines-macro-usage) #endif #if (defined(_MSC_VER) && (!defined(__GNUC__) && !defined(__clang__))) #if ((_MSC_VER >= 1900) && (defined(_HAS_CXX20) && (_HAS_CXX20 != 0))) #define WIDE_INTEGER_NODISCARD [[nodiscard]] // NOLINT(cppcoreguidelines-macro-usage) #else #define WIDE_INTEGER_NODISCARD #endif #else #if ((defined(__cplusplus) && (__cplusplus >= 201703L)) && (defined(__has_cpp_attribute) && (__has_cpp_attribute(nodiscard) >= 201603L))) #define WIDE_INTEGER_NODISCARD [[nodiscard]] // NOLINT(cppcoreguidelines-macro-usage) #else #define WIDE_INTEGER_NODISCARD #endif #endif #if defined(WIDE_INTEGER_NAMESPACE_BEGIN) || defined(WIDE_INTEGER_NAMESPACE_END) #error internal pre-processor macro already defined #endif #if defined(WIDE_INTEGER_NAMESPACE) #define WIDE_INTEGER_NAMESPACE_BEGIN namespace WIDE_INTEGER_NAMESPACE { // NOLINT(cppcoreguidelines-macro-usage) #define WIDE_INTEGER_NAMESPACE_END } // namespace WIDE_INTEGER_NAMESPACE // NOLINT(cppcoreguidelines-macro-usage) #else #define WIDE_INTEGER_NAMESPACE_BEGIN #define WIDE_INTEGER_NAMESPACE_END #endif // Forward declaration needed for class-friendship with the uintwide_t template class. namespace test_uintwide_t_edge { auto test_various_isolated_edge_cases() -> bool; } // namespace test_uintwide_t_edge WIDE_INTEGER_NAMESPACE_BEGIN #if(__cplusplus >= 201703L) namespace math::wide_integer::detail { #else namespace math { namespace wide_integer { namespace detail { // NOLINT(modernize-concat-nested-namespaces) #endif namespace iterator_detail { class input_iterator_tag { }; class output_iterator_tag { }; class forward_iterator_tag : public input_iterator_tag { }; class bidirectional_iterator_tag : public forward_iterator_tag { }; class random_access_iterator_tag : public bidirectional_iterator_tag { }; template class iterator_traits { public: using difference_type = typename iterator_type::difference_type; using value_type = typename iterator_type::value_type; using pointer = typename iterator_type::pointer; using reference = typename iterator_type::reference; using iterator_category = typename iterator_type::iterator_category; }; template class iterator_traits { public: using difference_type = ::std::ptrdiff_t; using value_type = T; using pointer = value_type*; using reference = value_type&; using iterator_category = random_access_iterator_tag; }; template class iterator_traits { public: using difference_type = ::std::ptrdiff_t; using value_type = T; using pointer = const value_type*; using reference = const value_type&; using iterator_category = random_access_iterator_tag; }; template struct my_iterator { using iterator_category = my_category; using value_type = my_value_type; using difference_type = my_difference_type; using pointer = my_pointer_type; using reference = my_reference_type; constexpr my_iterator() = default; }; template class reverse_iterator : public my_iterator::iterator_category, typename iterator_traits::value_type, typename iterator_traits::difference_type, typename iterator_traits::pointer, typename iterator_traits::reference> { public: using value_type = typename iterator_traits::value_type; using difference_type = typename iterator_traits::difference_type; using pointer = typename iterator_traits::pointer; using reference = typename iterator_traits::reference; using iterator_category = typename iterator_traits::iterator_category; constexpr reverse_iterator() = default; explicit constexpr reverse_iterator(iterator_type x) : current(x) { } template explicit constexpr reverse_iterator(const reverse_iterator& u) : current(u.current) { } // NOLINT(google-explicit-constructor,hicpp-explicit-conversions) WIDE_INTEGER_NODISCARD constexpr auto base() const -> iterator_type { return current; } constexpr auto operator* () const -> reference { iterator_type tmp = current; return *--tmp; } constexpr auto operator->() const -> pointer { return &(operator*()); } constexpr auto operator++() -> reverse_iterator& { --current; return *this; } constexpr auto operator--() -> reverse_iterator& { ++current; return *this; } constexpr auto operator++(int) -> reverse_iterator { reverse_iterator tmp = *this; --current; return tmp; } constexpr auto operator--(int) -> reverse_iterator { reverse_iterator tmp = *this; ++current; return tmp; } constexpr auto operator+=(typename reverse_iterator::difference_type n) -> reverse_iterator& { current -= n; return *this; } constexpr auto operator-=(typename reverse_iterator::difference_type n) -> reverse_iterator& { current += n; return *this; } constexpr auto operator[](typename reverse_iterator::difference_type n) const -> reference { return current[-n - 1]; } private: iterator_type current; // NOLINT(readability-identifier-naming) friend constexpr auto operator+(const reverse_iterator& x, typename reverse_iterator::difference_type n) -> reverse_iterator { return reverse_iterator(x.current - n); } friend constexpr auto operator-(const reverse_iterator& x, typename reverse_iterator::difference_type n) -> reverse_iterator { return reverse_iterator(x.current + n); } friend constexpr auto operator< (const reverse_iterator& x, const reverse_iterator& y) -> bool { return (x.current > y.current); } friend constexpr auto operator<=(const reverse_iterator& x, const reverse_iterator& y) -> bool { return (x.current >= y.current); } friend constexpr auto operator==(const reverse_iterator& x, const reverse_iterator& y) -> bool { return (x.current == y.current); } friend constexpr auto operator!=(const reverse_iterator& x, const reverse_iterator& y) -> bool { return (x.current != y.current); } friend constexpr auto operator>=(const reverse_iterator& x, const reverse_iterator& y) -> bool { return (x.current <= y.current); } friend constexpr auto operator> (const reverse_iterator& x, const reverse_iterator& y) -> bool { return (x.current < y.current); } friend constexpr auto operator-(const reverse_iterator& x, const reverse_iterator& y) -> typename reverse_iterator::difference_type { return (y.current - x.current); } friend constexpr auto operator+(typename reverse_iterator::difference_type n, const reverse_iterator& x) -> reverse_iterator { return reverse_iterator(x.current - n); } }; } // namespace iterator_detail // Forward declaration of: // Use a local, constexpr, unsafe implementation of the abs-function. template constexpr auto abs_unsafe(const ArithmeticType& val) -> ArithmeticType; // Use a local, constexpr, unsafe implementation of the fill-function. template constexpr auto fill_unsafe(DestinationIterator first, DestinationIterator last, ValueType val) -> void { while(first != last) { using local_destination_value_type = typename iterator_detail::iterator_traits::value_type; *first = static_cast(val); ++first; } } // Use a local, constexpr, unsafe implementation of the max-function. template constexpr auto max_unsafe(const ArithmeticType& left, const ArithmeticType& right) -> ArithmeticType { return ((left < right) ? right : left); } // Use a local, constexpr, unsafe implementation of the max-function. template constexpr auto min_unsafe(const ArithmeticType& left, const ArithmeticType& right) -> ArithmeticType { return ((right < left) ? right : left); } // Use a local, constexpr, unsafe implementation of the copy-function. template constexpr auto copy_unsafe(InputIterator first, InputIterator last, DestinationIterator dest) -> DestinationIterator { while(first != last) { using local_destination_value_type = typename iterator_detail::iterator_traits::value_type; #if (defined(__GNUC__) && (__GNUC__ > 9)) #pragma GCC diagnostic ignored "-Wstringop-overflow" #pragma GCC diagnostic ignored "-Wmaybe-uninitialized" #endif *dest++ = static_cast(*first++); #if (defined(__GNUC__) && (__GNUC__ > 9)) #pragma GCC diagnostic pop #pragma GCC diagnostic pop #endif } return dest; } // Use a local, constexpr, unsafe implementation of the copy-backward-function. template constexpr auto copy_backward_unsafe(InputIterator first, InputIterator last, DestinationIterator dest) -> DestinationIterator { using local_destination_value_type = typename iterator_detail::iterator_traits::value_type; while(first != last) { *(--dest) = static_cast(*(--last)); } return dest; } template constexpr auto swap_unsafe(T& left, T& right) noexcept -> void { T tmp { std::move(static_cast(left)) }; left = std::move(static_cast(right)); right = std::move(static_cast(tmp)); } template constexpr auto find_if_unsafe(InputIt first, InputIt last, UnaryPredicate p) -> InputIt { while(first != last) { if(p(*first)) { return first; } ++first; } return last; // LCOV_EXCL_LINE } template constexpr auto lower_bound_unsafe(ForwardIt first, ForwardIt last, const T& value) -> ForwardIt { using local_iterator_type = ForwardIt; using local_difference_type = typename iterator_detail::iterator_traits::difference_type; local_difference_type step { }; auto count = static_cast(last - first); // NOLINT(altera-id-dependent-backward-branch) local_iterator_type itr { }; while(count > static_cast(INT8_C(0))) // NOLINT(altera-id-dependent-backward-branch) { itr = first; step = static_cast(count / static_cast(INT8_C(2))); itr += step; if (*itr < value) { first = ++itr; count -= static_cast(step + static_cast(INT8_C(1))); } else { count = step; } } return first; } template constexpr auto binary_search_unsafe(ForwardIt first, ForwardIt last, const T& value) -> bool { first = lower_bound_unsafe(first, last, value); return ((!(first == last)) && (!(value < *first))); } namespace distance_detail { template constexpr auto do_distance_unsafe(It first, It last, detail::iterator_detail::random_access_iterator_tag) -> typename detail::iterator_detail::iterator_traits::difference_type // NOLINT(hicpp-named-parameter,readability-named-parameter) { using local_difference_type = typename detail::iterator_detail::iterator_traits::difference_type; return static_cast(last - first); } } // namespace distance_detail template constexpr auto distance_unsafe(It first, It last) -> typename iterator_detail::iterator_traits::difference_type { using local_iterator_category_type = typename iterator_detail::iterator_traits::iterator_category; return distance_detail::do_distance_unsafe ( first, last, local_iterator_category_type() ); } template constexpr auto equal_unsafe(InputIt1 first1, InputIt1 last1, InputIt2 first2) -> bool { while(first1 != last1) { if(!(*first1++ == *first2++)) { return false; } } return true; } template constexpr auto lexicographical_compare_unsafe(InputIt1 first1, InputIt1 last1, InputIt2 first2, InputIt2 last2) -> bool { for( ; (first1 != last1) && (first2 != last2); static_cast(++first1), static_cast(++first2)) { if(*first1 < *first2) { return true; } if(*first2 < *first1) { return false; } } return ((first1 == last1) && (first2 != last2)); } template constexpr auto iter_swap_unsafe(Iterator1 a, Iterator2 b) -> void { using local_value_type = typename iterator_detail::iterator_traits::value_type; swap_unsafe(static_cast(*a), static_cast(*b)); } template constexpr auto swap_ranges_unsafe(ForwardIt1 first1, ForwardIt1 last1, ForwardIt2 first2) -> ForwardIt2 { while(first1 != last1) { iter_swap_unsafe(first1, first2); ++first1; ++first2; } return first2; } template constexpr auto clz_unsafe(UnsignedIntegralType v) noexcept -> std::enable_if_t<( std::is_integral::value && std::is_unsigned::value), unsigned> { using local_unsigned_integral_type = UnsignedIntegralType; local_unsigned_integral_type yy_val { local_unsigned_integral_type { UINT8_C(0) } }; unsigned nn_val { static_cast(std::numeric_limits::digits) }; auto cc_val = // NOLINT(altera-id-dependent-backward-branch) static_cast ( std::numeric_limits::digits / static_cast(INT8_C(2)) ); do { yy_val = static_cast(v >> cc_val); if(yy_val != static_cast(UINT8_C(0))) { nn_val -= cc_val; v = yy_val; } cc_val >>= static_cast(UINT8_C(1)); } while(cc_val != static_cast(UINT8_C(0))); // NOLINT(altera-id-dependent-backward-branch) return static_cast ( static_cast(nn_val) - static_cast(v) ); } template constexpr auto ctz_unsafe(const UnsignedIntegralType v) noexcept -> std::enable_if_t<( std::is_integral::value && std::is_unsigned::value), unsigned> { using local_unsigned_integral_type = UnsignedIntegralType; constexpr auto local_digits = static_cast(std::numeric_limits::digits); const auto clz_mask = static_cast ( static_cast(~v) & static_cast(v - static_cast(UINT8_C(1))) ); return static_cast(local_digits - clz_unsafe(clz_mask)); } template constexpr auto gcd_unsafe(UnsignedIntegralType u, UnsignedIntegralType v) -> std::enable_if_t<( std::is_integral::value // NOLINT(altera-id-dependent-backward-branch) && std::is_unsigned::value), UnsignedIntegralType> { using local_unsigned_integral_type = UnsignedIntegralType; // Handle cases having (u != 0) and (v != 0). if(u == static_cast(UINT8_C(0))) { return v; } if(v == static_cast(UINT8_C(0))) { return u; } // Shift the greatest power of 2 dividing both u and v. const unsigned trz { static_cast(ctz_unsafe(u)) }; const unsigned shift_amount { detail::min_unsafe(trz, ctz_unsafe(v)) }; v >>= shift_amount; u >>= trz; do { // Reduce the GCD. v >>= ctz_unsafe(v); if(u > v) { swap_unsafe(u, v); } v -= u; } while(v != static_cast(UINT8_C(0))); // NOLINT(altera-id-dependent-backward-branch) return static_cast(u << shift_amount); } namespace array_detail { template class array { public: // Standard container-local type definitions. using size_type = ::std::size_t; using difference_type = ::std::ptrdiff_t; using value_type = T; using pointer = T*; using const_pointer = const T*; using reference = T&; using const_reference = const T&; using iterator = pointer; using const_iterator = const_pointer; using reverse_iterator = iterator_detail::reverse_iterator; using const_reverse_iterator = iterator_detail::reverse_iterator; value_type elems[N] { }; // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays,misc-non-private-member-variables-in-classes) static constexpr size_type static_size = N; WIDE_INTEGER_NODISCARD constexpr auto begin() -> iterator { return elems; } // NOLINT(cppcoreguidelines-pro-bounds-array-to-pointer-decay,hicpp-no-array-decay,cppcoreguidelines-pro-bounds-pointer-arithmetic) WIDE_INTEGER_NODISCARD constexpr auto end () -> iterator { return elems + N; } // NOLINT(cppcoreguidelines-pro-bounds-array-to-pointer-decay,hicpp-no-array-decay,cppcoreguidelines-pro-bounds-pointer-arithmetic) WIDE_INTEGER_NODISCARD constexpr auto begin() const -> const_iterator { return elems; } // NOLINT(cppcoreguidelines-pro-bounds-array-to-pointer-decay,hicpp-no-array-decay,cppcoreguidelines-pro-bounds-pointer-arithmetic) WIDE_INTEGER_NODISCARD constexpr auto end () const -> const_iterator { return elems + N; } // NOLINT(cppcoreguidelines-pro-bounds-array-to-pointer-decay,hicpp-no-array-decay,cppcoreguidelines-pro-bounds-pointer-arithmetic) WIDE_INTEGER_NODISCARD constexpr auto cbegin() const -> const_iterator { return elems; } // NOLINT(cppcoreguidelines-pro-bounds-array-to-pointer-decay,hicpp-no-array-decay,cppcoreguidelines-pro-bounds-pointer-arithmetic) WIDE_INTEGER_NODISCARD constexpr auto cend () const -> const_iterator { return elems + N; } // NOLINT(cppcoreguidelines-pro-bounds-array-to-pointer-decay,hicpp-no-array-decay,cppcoreguidelines-pro-bounds-pointer-arithmetic) WIDE_INTEGER_NODISCARD constexpr auto rbegin() -> reverse_iterator { return reverse_iterator(elems + N); } // NOLINT(cppcoreguidelines-pro-bounds-array-to-pointer-decay,hicpp-no-array-decay,cppcoreguidelines-pro-bounds-pointer-arithmetic) WIDE_INTEGER_NODISCARD constexpr auto rend () -> reverse_iterator { return reverse_iterator(elems); } // NOLINT(cppcoreguidelines-pro-bounds-array-to-pointer-decay,hicpp-no-array-decay,cppcoreguidelines-pro-bounds-pointer-arithmetic) WIDE_INTEGER_NODISCARD constexpr auto rbegin() const -> const_reverse_iterator { return const_reverse_iterator(elems + N); } // NOLINT(cppcoreguidelines-pro-bounds-array-to-pointer-decay,hicpp-no-array-decay,cppcoreguidelines-pro-bounds-pointer-arithmetic) WIDE_INTEGER_NODISCARD constexpr auto rend () const -> const_reverse_iterator { return const_reverse_iterator(elems); } // NOLINT(cppcoreguidelines-pro-bounds-array-to-pointer-decay,hicpp-no-array-decay,cppcoreguidelines-pro-bounds-pointer-arithmetic) WIDE_INTEGER_NODISCARD constexpr auto crbegin() const -> const_reverse_iterator { return const_reverse_iterator(elems + N); } // NOLINT(cppcoreguidelines-pro-bounds-array-to-pointer-decay,hicpp-no-array-decay,cppcoreguidelines-pro-bounds-pointer-arithmetic) WIDE_INTEGER_NODISCARD constexpr auto crend () const -> const_reverse_iterator { return const_reverse_iterator(elems); } // NOLINT(cppcoreguidelines-pro-bounds-array-to-pointer-decay,hicpp-no-array-decay,cppcoreguidelines-pro-bounds-pointer-arithmetic) WIDE_INTEGER_NODISCARD constexpr auto operator[](const size_type i) -> reference { return elems[i]; } // NOLINT(cppcoreguidelines-pro-bounds-constant-array-index) WIDE_INTEGER_NODISCARD constexpr auto operator[](const size_type i) const -> const_reference { return elems[i]; } // NOLINT(cppcoreguidelines-pro-bounds-constant-array-index) WIDE_INTEGER_NODISCARD constexpr auto at(const size_type i) -> reference { return elems[i]; } // NOLINT(cppcoreguidelines-pro-bounds-constant-array-index) WIDE_INTEGER_NODISCARD constexpr auto at(const size_type i) const -> const_reference { return elems[i]; } // NOLINT(cppcoreguidelines-pro-bounds-constant-array-index) WIDE_INTEGER_NODISCARD constexpr auto front() -> reference { return elems[static_cast(UINT8_C(0))]; } WIDE_INTEGER_NODISCARD constexpr auto front() const -> const_reference { return elems[static_cast(UINT8_C(0))]; } WIDE_INTEGER_NODISCARD constexpr auto back() -> reference { return elems[N - UINT8_C(1)]; } WIDE_INTEGER_NODISCARD constexpr auto back() const -> const_reference { return elems[N - UINT8_C(1)]; } WIDE_INTEGER_NODISCARD static constexpr auto size() -> size_type { return N; } WIDE_INTEGER_NODISCARD static constexpr auto empty() -> bool { return false; } WIDE_INTEGER_NODISCARD static constexpr auto max_size() -> size_type { return N; } template constexpr auto swap(array& y) noexcept -> void { swap_ranges_unsafe(begin(), end(), y.begin()); } WIDE_INTEGER_NODISCARD constexpr auto data() const -> const_pointer { return elems; } // NOLINT(cppcoreguidelines-pro-bounds-array-to-pointer-decay,hicpp-no-array-decay) WIDE_INTEGER_NODISCARD constexpr auto data() -> pointer { return elems; } // NOLINT(cppcoreguidelines-pro-bounds-array-to-pointer-decay,hicpp-no-array-decay) WIDE_INTEGER_NODISCARD constexpr auto c_array() -> pointer { return elems; } template constexpr auto operator=(const array& y) -> array& { copy_unsafe(y.begin(), y.end(), begin()); return *this; } constexpr auto assign(const value_type& value) -> void { fill_unsafe(elems, elems + N, value); // NOLINT(cppcoreguidelines-pro-bounds-array-to-pointer-decay,hicpp-no-array-decay,cppcoreguidelines-pro-bounds-pointer-arithmetic) } constexpr auto fill(const value_type& value) -> void { assign(value); } friend constexpr auto operator==(const array& left, const array& right) -> bool { return equal_unsafe(left.begin(), left.end(), right.begin()); } friend constexpr auto operator<(const array& left, const array& right) -> bool { return lexicographical_compare_unsafe(left.begin(), left.end(), right.begin(), right.end()); } friend constexpr auto operator!=(const array& left, const array& right) -> bool { return (!(left == right)); } friend constexpr auto operator> (const array& left, const array& right) -> bool { return (right < left); } friend constexpr auto operator>=(const array& left, const array& right) -> bool { return (!(left < right)); } friend constexpr auto operator<=(const array& left, const array& right) -> bool { return (!(right < left)); } }; template constexpr auto swap(array& x, array& y) noexcept -> void { swap_ranges_unsafe(x.begin(), x.end(), y.begin()); } template class tuple_size; template class tuple_size> : public std::integral_constant { }; template class tuple_element; template class tuple_element > { static_assert(I < N, "Sorry, tuple_element index is out of bounds."); using type = T; }; } // namespace array_detail #if(__cplusplus >= 201703L) } // namespace math::wide_integer::detail #else } // namespace detail } // namespace wide_integer } // namespace math #endif WIDE_INTEGER_NAMESPACE_END #if !defined(WIDE_INTEGER_DISABLE_IMPLEMENT_UTIL_DYNAMIC_ARRAY) WIDE_INTEGER_NAMESPACE_BEGIN namespace util { template, typename SizeType = ::std::size_t, typename DiffType = ::std::ptrdiff_t> class dynamic_array; template class dynamic_array { public: // Type definitions. using allocator_type = typename std::allocator_traits::template rebind_alloc; using value_type = typename allocator_type::value_type; using reference = value_type&; using const_reference = const value_type&; using iterator = value_type*; using const_iterator = const value_type*; using pointer = value_type*; using const_pointer = const value_type*; using size_type = SizeType; using difference_type = DiffType; #if defined(WIDE_INTEGER_NAMESPACE) using reverse_iterator = WIDE_INTEGER_NAMESPACE::math::wide_integer::detail::iterator_detail::reverse_iterator< value_type*>; using const_reverse_iterator = WIDE_INTEGER_NAMESPACE::math::wide_integer::detail::iterator_detail::reverse_iterator; #else using reverse_iterator = ::math::wide_integer::detail::iterator_detail::reverse_iterator< value_type*>; using const_reverse_iterator = ::math::wide_integer::detail::iterator_detail::reverse_iterator; #endif // Constructors. constexpr dynamic_array() = delete; explicit constexpr dynamic_array(size_type count_in, const_reference value_in = value_type(), const allocator_type& alloc_in = allocator_type()) : elem_count(count_in) { if(elem_count > static_cast(UINT8_C(0))) { allocator_type my_alloc(alloc_in); elems = std::allocator_traits::allocate(my_alloc, elem_count); iterator it = begin(); while(it != end()) { std::allocator_traits::construct(my_alloc, it, value_in); ++it; } } } constexpr dynamic_array(const dynamic_array& other) : elem_count(other.size()) { allocator_type my_alloc; if(elem_count > static_cast(UINT8_C(0))) { elems = std::allocator_traits::allocate(my_alloc, elem_count); } #if defined(WIDE_INTEGER_NAMESPACE) WIDE_INTEGER_NAMESPACE::math::wide_integer::detail::copy_unsafe(other.elems, other.elems + elem_count, elems); #else ::math::wide_integer::detail::copy_unsafe(other.elems, other.elems + elem_count, elems); #endif } template constexpr dynamic_array(input_iterator first, input_iterator last, const allocator_type& alloc_in = allocator_type()) : elem_count(static_cast(last - first)) { allocator_type my_alloc(alloc_in); if(elem_count > static_cast(UINT8_C(0))) { elems = std::allocator_traits::allocate(my_alloc, elem_count); } #if defined(WIDE_INTEGER_NAMESPACE) WIDE_INTEGER_NAMESPACE::math::wide_integer::detail::copy_unsafe(first, last, elems); #else ::math::wide_integer::detail::copy_unsafe(first, last, elems); #endif } constexpr dynamic_array(std::initializer_list lst, const allocator_type& alloc_in = allocator_type()) : elem_count(lst.size()) { allocator_type my_alloc(alloc_in); if(elem_count > static_cast(UINT8_C(0))) { elems = std::allocator_traits::allocate(my_alloc, elem_count); } #if defined(WIDE_INTEGER_NAMESPACE) WIDE_INTEGER_NAMESPACE::math::wide_integer::detail::copy_unsafe(lst.begin(), lst.end(), elems); #else ::math::wide_integer::detail::copy_unsafe(lst.begin(), lst.end(), elems); #endif } // Move constructor. constexpr dynamic_array(dynamic_array&& other) noexcept : elem_count(other.elem_count), elems (other.elems) { other.elem_count = static_cast(UINT8_C(0)); other.elems = nullptr; } // Destructor. //constexpr virtual ~dynamic_array() { if(!empty()) { using local_allocator_traits_type = std::allocator_traits; allocator_type my_alloc; auto p = begin(); // NOLINT(llvm-qualified-auto,readability-qualified-auto) while(p != end()) { local_allocator_traits_type::destroy(my_alloc, p); ++p; } // Destroy the elements and deallocate the range. local_allocator_traits_type::deallocate(my_alloc, elems, elem_count); } } // Assignment operator. constexpr auto operator=(const dynamic_array& other) -> dynamic_array& { if(this != &other) { #if defined(WIDE_INTEGER_NAMESPACE) WIDE_INTEGER_NAMESPACE::math::wide_integer::detail::copy_unsafe #else ::math::wide_integer::detail::copy_unsafe #endif ( other.elems, #if defined(WIDE_INTEGER_NAMESPACE) other.elems + WIDE_INTEGER_NAMESPACE::math::wide_integer::detail::min_unsafe #else other.elems + ::math::wide_integer::detail::min_unsafe #endif ( elem_count, other.elem_count ), elems ); } return *this; } // Move assignment operator. constexpr auto operator=(dynamic_array&& other) noexcept -> dynamic_array& { #if defined(WIDE_INTEGER_NAMESPACE) WIDE_INTEGER_NAMESPACE::math::wide_integer::detail::swap_unsafe(elem_count, other.elem_count); WIDE_INTEGER_NAMESPACE::math::wide_integer::detail::swap_unsafe(elems, other.elems); #else ::math::wide_integer::detail::swap_unsafe(elem_count, other.elem_count); ::math::wide_integer::detail::swap_unsafe(elems, other.elems); #endif return *this; } // Iterator members: constexpr auto begin () -> iterator { return elems; } constexpr auto end () -> iterator { return elems + elem_count; } constexpr auto begin () const -> const_iterator { return elems; } constexpr auto end () const -> const_iterator { return elems + elem_count; } constexpr auto cbegin () const -> const_iterator { return elems; } constexpr auto cend () const -> const_iterator { return elems + elem_count; } constexpr auto rbegin () -> reverse_iterator { return reverse_iterator(elems + elem_count); } constexpr auto rend () -> reverse_iterator { return reverse_iterator(elems); } constexpr auto rbegin () const -> const_reverse_iterator { return const_reverse_iterator(elems + elem_count); } constexpr auto rend () const -> const_reverse_iterator { return const_reverse_iterator(elems); } constexpr auto crbegin() const -> const_reverse_iterator { return const_reverse_iterator(elems + elem_count); } constexpr auto crend () const -> const_reverse_iterator { return const_reverse_iterator(elems); } // Raw pointer access. constexpr auto data() -> pointer { return elems; } constexpr auto data() const -> const_pointer { return elems; } // Size and capacity. constexpr auto size () const noexcept -> size_type { return elem_count; } constexpr auto max_size() const noexcept -> size_type { return elem_count; } constexpr auto empty () const noexcept -> bool { return (elem_count == static_cast(UINT8_C(0))); } // Element access members. constexpr auto operator[](const size_type i) -> reference { return elems[i]; } constexpr auto operator[](const size_type i) const -> const_reference { return elems[i]; } constexpr auto front() -> reference { return elems[static_cast(UINT8_C(0))]; } constexpr auto front() const -> const_reference { return elems[static_cast(UINT8_C(0))]; } constexpr auto back() -> reference { return ((elem_count > static_cast(UINT8_C(0))) ? elems[static_cast(elem_count - static_cast(UINT8_C(1)))] : elems[static_cast(UINT8_C(0))]); } constexpr auto back() const -> const_reference { return ((elem_count > static_cast(UINT8_C(0))) ? elems[static_cast(elem_count - static_cast(UINT8_C(1)))] : elems[static_cast(UINT8_C(0))]); } constexpr auto at(const size_type i) -> reference { return ((i < elem_count) ? elems[i] : elems[static_cast(UINT8_C(0))]); } constexpr auto at(const size_type i) const -> const_reference { return ((i < elem_count) ? elems[i] : elems[static_cast(UINT8_C(0))]); } // Element manipulation members. constexpr auto fill(const value_type& value_in) -> void { #if defined(WIDE_INTEGER_NAMESPACE) WIDE_INTEGER_NAMESPACE::math::wide_integer::detail::fill_unsafe(begin(), begin() + elem_count, value_in); #else ::math::wide_integer::detail::fill_unsafe(begin(), begin() + elem_count, value_in); #endif } constexpr auto swap(dynamic_array& other) noexcept -> void { if(this != &other) { #if defined(WIDE_INTEGER_NAMESPACE) WIDE_INTEGER_NAMESPACE::math::wide_integer::detail::swap_unsafe(elems, other.elems); WIDE_INTEGER_NAMESPACE::math::wide_integer::detail::swap_unsafe(elem_count, other.elem_count); #else ::math::wide_integer::detail::swap_unsafe(elems, other.elems); ::math::wide_integer::detail::swap_unsafe(elem_count, other.elem_count); #endif } } constexpr auto swap(dynamic_array&& other) noexcept -> void { dynamic_array tmp { std::move(*this) }; *this = std::move(static_cast(other)); other = std::move(static_cast(tmp)); } private: mutable size_type elem_count; // NOLINT(readability-identifier-naming) pointer elems { nullptr }; // NOLINT(readability-identifier-naming,altera-id-dependent-backward-branch) friend constexpr auto operator==(const dynamic_array& lhs, const dynamic_array& rhs) -> bool { return ( (lhs.size() == rhs.size()) && ( lhs.empty() #if defined(WIDE_INTEGER_NAMESPACE) || WIDE_INTEGER_NAMESPACE::math::wide_integer::detail::equal_unsafe(lhs.cbegin(), lhs.cend(), rhs.cbegin()) #else || ::math::wide_integer::detail::equal_unsafe(lhs.cbegin(), lhs.cend(), rhs.cbegin()) #endif ) ); } friend constexpr auto operator<(const dynamic_array& lhs, const dynamic_array& rhs) -> bool { bool b_result { }; if(lhs.empty()) { b_result = (!rhs.empty()); } else { // Note: Use lexicographical_compare here. If the dynamic arrays // have unequal sizes, then simply ignore the size differences. b_result = #if defined(WIDE_INTEGER_NAMESPACE) WIDE_INTEGER_NAMESPACE::math::wide_integer::detail::lexicographical_compare_unsafe #else ::math::wide_integer::detail::lexicographical_compare_unsafe #endif ( lhs.cbegin(), lhs.cend(), rhs.cbegin(), rhs.cend() ); } return b_result; } friend constexpr auto operator!=(const dynamic_array& lhs, const dynamic_array& rhs) -> bool { return (!(lhs == rhs)); } friend constexpr auto operator> (const dynamic_array& lhs, const dynamic_array& rhs) -> bool { return (rhs < lhs); } friend constexpr auto operator>=(const dynamic_array& lhs, const dynamic_array& rhs) -> bool { return (!(lhs < rhs)); } friend constexpr auto operator<=(const dynamic_array& lhs, const dynamic_array& rhs) -> bool { return (!(rhs < lhs)); } }; template constexpr auto swap(dynamic_array& x, dynamic_array& y) noexcept -> void { x.swap(y); } } // namespace util WIDE_INTEGER_NAMESPACE_END WIDE_INTEGER_NAMESPACE_BEGIN #if(__cplusplus >= 201703L) namespace math::wide_integer::detail { #else namespace math { namespace wide_integer { namespace detail { // NOLINT(modernize-concat-nested-namespaces) #endif using util::dynamic_array; #if(__cplusplus >= 201703L) } // namespace math::wide_integer::detail #else } // namespace detail } // namespace wide_integer } // namespace math #endif WIDE_INTEGER_NAMESPACE_END #else #include WIDE_INTEGER_NAMESPACE_BEGIN #if(__cplusplus >= 201703L) namespace math::wide_integer::detail { #else namespace math { namespace wide_integer { namespace detail { // NOLINT(modernize-concat-nested-namespaces) #endif using util::dynamic_array; #if(__cplusplus >= 201703L) } // namespace math::wide_integer::detail #else } // namespace detail } // namespace wide_integer } // namespace math #endif WIDE_INTEGER_NAMESPACE_END #endif WIDE_INTEGER_NAMESPACE_BEGIN #if(__cplusplus >= 201703L) namespace math::wide_integer { #else namespace math { namespace wide_integer { // NOLINT(modernize-concat-nested-namespaces) #endif namespace detail { using size_t = std::uint32_t; using ptrdiff_t = std::int32_t; static_assert(( (std::numeric_limits::digits >= std::numeric_limits::digits) && (std::numeric_limits::digits + 1 >= std::numeric_limits::digits)), "Error: size type and pointer difference type must be at least 16 bits in width (or wider)"); template struct verify_power_of_two // NOLINT(altera-struct-pack-align) { // TBD: Which powers should be checked if size_t is not 32 bits? static constexpr auto conditional_value = (Width2 == static_cast(1ULL << 0U)) || (Width2 == static_cast(1ULL << 1U)) || (Width2 == static_cast(1ULL << 2U)) || (Width2 == static_cast(1ULL << 3U)) || (Width2 == static_cast(1ULL << 4U)) || (Width2 == static_cast(1ULL << 5U)) || (Width2 == static_cast(1ULL << 6U)) || (Width2 == static_cast(1ULL << 7U)) || (Width2 == static_cast(1ULL << 8U)) || (Width2 == static_cast(1ULL << 9U)) || (Width2 == static_cast(1ULL << 10U)) || (Width2 == static_cast(1ULL << 11U)) || (Width2 == static_cast(1ULL << 12U)) || (Width2 == static_cast(1ULL << 13U)) || (Width2 == static_cast(1ULL << 14U)) || (Width2 == static_cast(1ULL << 15U)) || (Width2 == static_cast(1ULL << 16U)) || (Width2 == static_cast(1ULL << 17U)) || (Width2 == static_cast(1ULL << 18U)) || (Width2 == static_cast(1ULL << 19U)) || (Width2 == static_cast(1ULL << 20U)) || (Width2 == static_cast(1ULL << 21U)) || (Width2 == static_cast(1ULL << 22U)) || (Width2 == static_cast(1ULL << 23U)) || (Width2 == static_cast(1ULL << 24U)) || (Width2 == static_cast(1ULL << 25U)) || (Width2 == static_cast(1ULL << 26U)) || (Width2 == static_cast(1ULL << 27U)) || (Width2 == static_cast(1ULL << 28U)) || (Width2 == static_cast(1ULL << 29U)) || (Width2 == static_cast(1ULL << 30U)) || (Width2 == static_cast(1ULL << 31U)) ; }; template struct uint_type_helper { private: static constexpr auto bit_count () -> size_t { return BitCount; } static constexpr auto bit_count_lo() -> size_t { return static_cast(UINT8_C(8)); } #if defined(WIDE_INTEGER_HAS_LIMB_TYPE_UINT64) static constexpr auto bit_count_hi() -> size_t { return static_cast(UINT8_C(128)); } #else static constexpr auto bit_count_hi() -> size_t { return static_cast(UINT8_C(64)); } #endif static_assert(( ((bit_count() >= bit_count_lo()) && (BitCount <= bit_count_hi())) // NOLINT(cppcoreguidelines-avoid-magic-numbers,readability-magic-numbers) && (verify_power_of_two::conditional_value)), "Error: uint_type_helper is not intended to be used for this BitCount"); public: using exact_unsigned_type = std::uintmax_t; using exact_signed_type = std::intmax_t; using fast_unsigned_type = std::uintmax_t; using fast_signed_type = std::intmax_t; }; template struct uint_type_helper(UINT8_C( 8)))>> { using exact_unsigned_type = std::uint8_t; using exact_signed_type = std::int8_t; using fast_unsigned_type = std::uint_fast8_t; using fast_signed_type = std::int_fast8_t; }; template struct uint_type_helper= static_cast(UINT8_C( 9))) && (BitCount <= static_cast(UINT8_C( 16)))>> { using exact_unsigned_type = std::uint16_t; using exact_signed_type = std::int16_t; using fast_unsigned_type = std::uint_fast16_t; using fast_signed_type = std::int_fast16_t; }; template struct uint_type_helper= static_cast(UINT8_C(17))) && (BitCount <= static_cast(UINT8_C( 32)))>> { using exact_unsigned_type = std::uint32_t; using exact_signed_type = std::int32_t; using fast_unsigned_type = std::uint_fast32_t; using fast_signed_type = std::int_fast32_t; }; template struct uint_type_helper= static_cast(UINT8_C(33))) && (BitCount <= static_cast(UINT8_C( 64)))>> { using exact_unsigned_type = std::uint64_t; using exact_signed_type = std::int64_t; using fast_unsigned_type = std::uint_fast64_t; using fast_signed_type = std::int_fast64_t; }; #if defined(WIDE_INTEGER_HAS_LIMB_TYPE_UINT64) #if (defined(__GNUC__) && !defined(__clang__)) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wpedantic" #endif template struct uint_type_helper= static_cast(UINT8_C(65))) && (BitCount <= static_cast(UINT8_C(128)))>> { using exact_unsigned_type = unsigned __int128; using exact_signed_type = signed __int128; using fast_unsigned_type = unsigned __int128; using fast_signed_type = signed __int128; }; #if (defined(__GNUC__) && !defined(__clang__)) #pragma GCC diagnostic pop #endif #endif using unsigned_fast_type = typename uint_type_helper(std::numeric_limits::digits + 0)>::fast_unsigned_type; using signed_fast_type = typename uint_type_helper(std::numeric_limits::digits + 1)>::fast_signed_type; #if !defined(WIDE_INTEGER_DISABLE_FLOAT_INTEROP) namespace my_own { template constexpr auto frexp (FloatingPointType x, int* expptr) -> std::enable_if_t<(std::is_floating_point::value && std::numeric_limits::is_iec559 ), FloatingPointType>; template constexpr auto frexp (FloatingPointType x, int* expptr) -> std::enable_if_t<(std::is_floating_point::value && (!std::numeric_limits::is_iec559)), FloatingPointType>; template constexpr auto (isfinite)(FloatingPointType x) -> std::enable_if_t<(std::is_floating_point::value && std::numeric_limits::is_iec559 ), bool>; template constexpr auto (isfinite)(FloatingPointType x) -> std::enable_if_t<(std::is_floating_point::value && (!std::numeric_limits::is_iec559)), bool>; } // namespace my_own #endif template constexpr auto import_export_helper( ForwardIterator in, OutputIterator out, const signed_fast_type total_bits_to_use, // NOLINT(bugprone-easily-swappable-parameters) const unsigned_fast_type chunk_size_in, const unsigned_fast_type chunk_size_out) -> OutputIterator { const auto size_to_loop_through = (detail::max_unsafe) ( static_cast(total_bits_to_use - static_cast(INT8_C(1))), static_cast(INT8_C(-1)) ); if(size_to_loop_through > static_cast(INT8_C(-1))) { using local_output_value_type = typename detail::iterator_detail::iterator_traits::value_type; *out = static_cast(UINT8_C(0)); for(auto i = size_to_loop_through; i >= static_cast(INT8_C(0)); // NOLINT(altera-id-dependent-backward-branch) --i) { const auto input_bpos = static_cast ( static_cast(i) % chunk_size_in ); using local_input_value_type = typename detail::iterator_detail::iterator_traits::value_type; const auto input_bval_is_set = ( static_cast ( *in & static_cast(static_cast(UINT8_C(1)) << input_bpos) ) != static_cast(UINT8_C(0)) ); const auto result_bpos = static_cast ( static_cast(i) % chunk_size_out ); if(input_bval_is_set) { *out = static_cast ( *out | static_cast ( static_cast(UINT8_C(1)) << result_bpos ) ); } const auto go_to_next_result_elem = (result_bpos == static_cast(UINT8_C(0))); if(go_to_next_result_elem && (i != static_cast(INT8_C(0)))) { *(++out) = static_cast(UINT8_C(0)); } const auto go_to_next_input_elem = (input_bpos == static_cast(UINT8_C(0))); if(go_to_next_input_elem && (i != static_cast(INT8_C(0)))) { ++in; } } } return out; } template constexpr auto div_maker_recursive(NumericType& val_to_divide, const NumericType& denom, const int power) -> void // NOLINT(misc-no-recursion) { if(power > 0) { div_maker_recursive(val_to_divide /= denom, denom, power - 1); // NOLINT(misc-no-recursion) } } } // namespace detail using detail::size_t; using detail::ptrdiff_t; using detail::unsigned_fast_type; using detail::signed_fast_type; // Forward declaration of the uintwide_t template class. template class uintwide_t; // Forward declarations of non-member binary add, sub, mul, div, mod of (uintwide_t op uintwide_t). template constexpr auto operator+(const uintwide_t& u, const uintwide_t& v) -> uintwide_t; template constexpr auto operator-(const uintwide_t& u, const uintwide_t& v) -> uintwide_t; template constexpr auto operator*(const uintwide_t& u, const uintwide_t& v) -> uintwide_t; template constexpr auto operator/(const uintwide_t& u, const uintwide_t& v) -> uintwide_t; template constexpr auto operator%(const uintwide_t& u, const uintwide_t& v) -> uintwide_t; // Forward declarations of non-member binary logic operations of (uintwide_t op uintwide_t). template constexpr auto operator| (const uintwide_t& u, const uintwide_t& v) -> uintwide_t; template constexpr auto operator^ (const uintwide_t& u, const uintwide_t& v) -> uintwide_t; template constexpr auto operator& (const uintwide_t& u, const uintwide_t& v) -> uintwide_t; // Forward declarations of non-member binary add, sub, mul, div, mod of (uintwide_t op IntegralType). template constexpr auto operator+(const uintwide_t& u, const IntegralType& v) -> std::enable_if_t::value, uintwide_t>; template constexpr auto operator-(const uintwide_t& u, const IntegralType& v) -> std::enable_if_t::value, uintwide_t>; template constexpr auto operator*(const uintwide_t& u, const IntegralType& v) -> std::enable_if_t::value, uintwide_t>; template constexpr auto operator/(const uintwide_t& u, const IntegralType& v) -> std::enable_if_t::value, uintwide_t>; template constexpr auto operator%(const uintwide_t& u, const IntegralType& v) -> std::enable_if_t<( std::is_integral::value && std::is_signed::value), uintwide_t>; template constexpr auto operator%(const uintwide_t& u, const IntegralType& v) -> std::enable_if_t<( std::is_integral ::value && std::is_unsigned ::value && (std::numeric_limits::digits <= std::numeric_limits::digits)), typename uintwide_t::limb_type>; template constexpr auto operator%(const uintwide_t& u, const IntegralType& v) -> std::enable_if_t<( std::is_integral ::value && std::is_unsigned ::value && (std::numeric_limits::digits > std::numeric_limits::digits)), uintwide_t>; // Forward declarations of non-member binary add, sub, mul, div, mod of (IntegralType op uintwide_t). template constexpr auto operator+(const IntegralType& u, const uintwide_t& v) -> std::enable_if_t::value, uintwide_t>; template constexpr auto operator-(const IntegralType& u, const uintwide_t& v) -> std::enable_if_t::value, uintwide_t>; template constexpr auto operator*(const IntegralType& u, const uintwide_t& v) -> std::enable_if_t::value, uintwide_t>; template constexpr auto operator/(const IntegralType& u, const uintwide_t& v) -> std::enable_if_t::value, uintwide_t>; template constexpr auto operator%(const IntegralType& u, const uintwide_t& v) -> std::enable_if_t::value, uintwide_t>; #if !defined(WIDE_INTEGER_DISABLE_FLOAT_INTEROP) // Forward declarations of non-member binary add, sub, mul, div, mod of (uintwide_t op FloatingPointType). template constexpr auto operator+(const uintwide_t& u, const FloatingPointType& f) -> std::enable_if_t::value, uintwide_t>; template constexpr auto operator-(const uintwide_t& u, const FloatingPointType& f) -> std::enable_if_t::value, uintwide_t>; template constexpr auto operator*(const uintwide_t& u, const FloatingPointType& f) -> std::enable_if_t::value, uintwide_t>; template constexpr auto operator/(const uintwide_t& u, const FloatingPointType& f) -> std::enable_if_t::value, uintwide_t>; template constexpr auto operator%(const uintwide_t& u, const FloatingPointType& f) -> std::enable_if_t::value, uintwide_t>; // Forward declarations of non-member binary add, sub, mul, div, mod of (FloatingPointType op uintwide_t). template constexpr auto operator+(const FloatingPointType& f, const uintwide_t& v) -> std::enable_if_t::value, uintwide_t>; template constexpr auto operator-(const FloatingPointType& f, const uintwide_t& v) -> std::enable_if_t::value, uintwide_t>; template constexpr auto operator*(const FloatingPointType& f, const uintwide_t& v) -> std::enable_if_t::value, uintwide_t>; template constexpr auto operator/(const FloatingPointType& f, const uintwide_t& v) -> std::enable_if_t::value, uintwide_t>; template constexpr auto operator%(const FloatingPointType& f, const uintwide_t& v) -> std::enable_if_t::value, uintwide_t>; #endif // Forward declarations of non-member binary logic operations of (uintwide_t op IntegralType). template constexpr auto operator|(const uintwide_t& u, const IntegralType& v) -> std::enable_if_t::value, uintwide_t>; template constexpr auto operator^(const uintwide_t& u, const IntegralType& v) -> std::enable_if_t::value, uintwide_t>; template constexpr auto operator&(const uintwide_t& u, const IntegralType& v) -> std::enable_if_t::value, uintwide_t>; // Forward declarations of non-member binary binary logic operations of (IntegralType op uintwide_t). template constexpr auto operator|(const IntegralType& u, const uintwide_t& v) -> std::enable_if_t::value, uintwide_t>; template constexpr auto operator^(const IntegralType& u, const uintwide_t& v) -> std::enable_if_t::value, uintwide_t>; template constexpr auto operator&(const IntegralType& u, const uintwide_t& v) -> std::enable_if_t::value, uintwide_t>; // Forward declarations of non-member shift functions of (uintwide_t shift IntegralType). template constexpr auto operator<<(const uintwide_t& u, const IntegralType n) -> std::enable_if_t::value, uintwide_t>; // NOLINT(readability-avoid-const-params-in-decls) template constexpr auto operator>>(const uintwide_t& u, const IntegralType n) -> std::enable_if_t::value, uintwide_t>; // NOLINT(readability-avoid-const-params-in-decls) // Forward declarations of non-member comparison functions of (uintwide_t cmp uintwide_t). template constexpr auto operator==(const uintwide_t& u, const uintwide_t& v) -> bool; template constexpr auto operator!=(const uintwide_t& u, const uintwide_t& v) -> bool; template constexpr auto operator> (const uintwide_t& u, const uintwide_t& v) -> bool; template constexpr auto operator< (const uintwide_t& u, const uintwide_t& v) -> bool; template constexpr auto operator>=(const uintwide_t& u, const uintwide_t& v) -> bool; template constexpr auto operator<=(const uintwide_t& u, const uintwide_t& v) -> bool; // Forward declarations of non-member comparison functions of (uintwide_t cmp IntegralType). template constexpr auto operator==(const uintwide_t& u, const IntegralType& v) -> std::enable_if_t::value, bool>; template constexpr auto operator!=(const uintwide_t& u, const IntegralType& v) -> std::enable_if_t::value, bool>; template constexpr auto operator> (const uintwide_t& u, const IntegralType& v) -> std::enable_if_t::value, bool>; template constexpr auto operator< (const uintwide_t& u, const IntegralType& v) -> std::enable_if_t::value, bool>; template constexpr auto operator>=(const uintwide_t& u, const IntegralType& v) -> std::enable_if_t::value, bool>; template constexpr auto operator<=(const uintwide_t& u, const IntegralType& v) -> std::enable_if_t::value, bool>; // Forward declarations of non-member comparison functions of (IntegralType cmp uintwide_t). template constexpr auto operator==(const IntegralType& u, const uintwide_t& v) -> std::enable_if_t::value, bool>; template constexpr auto operator!=(const IntegralType& u, const uintwide_t& v) -> std::enable_if_t::value, bool>; template constexpr auto operator> (const IntegralType& u, const uintwide_t& v) -> std::enable_if_t::value, bool>; template constexpr auto operator< (const IntegralType& u, const uintwide_t& v) -> std::enable_if_t::value, bool>; template constexpr auto operator>=(const IntegralType& u, const uintwide_t& v) -> std::enable_if_t::value, bool>; template constexpr auto operator<=(const IntegralType& u, const uintwide_t& v) -> std::enable_if_t::value, bool>; #if !defined(WIDE_INTEGER_DISABLE_FLOAT_INTEROP) // Non-member comparison functions of (uintwide_t cmp FloatingPointType). template constexpr auto operator==(const uintwide_t& u, const FloatingPointType& f) -> std::enable_if_t::value, bool>; template constexpr auto operator!=(const uintwide_t& u, const FloatingPointType& f) -> std::enable_if_t::value, bool>; template constexpr auto operator> (const uintwide_t& u, const FloatingPointType& f) -> std::enable_if_t::value, bool>; template constexpr auto operator< (const uintwide_t& u, const FloatingPointType& f) -> std::enable_if_t::value, bool>; template constexpr auto operator>=(const uintwide_t& u, const FloatingPointType& f) -> std::enable_if_t::value, bool>; template constexpr auto operator<=(const uintwide_t& u, const FloatingPointType& f) -> std::enable_if_t::value, bool>; // Non-member comparison functions of (FloatingPointType cmp uintwide_t). template constexpr auto operator==(const FloatingPointType& f, const uintwide_t& v) -> std::enable_if_t::value, bool>; template constexpr auto operator!=(const FloatingPointType& f, const uintwide_t& v) -> std::enable_if_t::value, bool>; template constexpr auto operator> (const FloatingPointType& f, const uintwide_t& v) -> std::enable_if_t::value, bool>; template constexpr auto operator< (const FloatingPointType& f, const uintwide_t& v) -> std::enable_if_t::value, bool>; template constexpr auto operator>=(const FloatingPointType& f, const uintwide_t& v) -> std::enable_if_t::value, bool>; template constexpr auto operator<=(const FloatingPointType& f, const uintwide_t& v) -> std::enable_if_t::value, bool>; #endif #if !defined(WIDE_INTEGER_DISABLE_IOSTREAM) // Forward declarations of I/O streaming functions. template auto operator<<(std::basic_ostream& out, const uintwide_t& x) -> std::basic_ostream&; template auto operator>>(std::basic_istream& in, uintwide_t& x) -> std::basic_istream&; #endif // Forward declarations of various number-theoretical tools. template constexpr auto swap(uintwide_t& x, uintwide_t& y) noexcept -> void; template constexpr auto lsb(const uintwide_t& x) -> unsigned_fast_type; template constexpr auto msb(const uintwide_t& x) -> unsigned_fast_type; template constexpr auto abs(const uintwide_t& x) -> uintwide_t; template constexpr auto sqrt(const uintwide_t& m) -> uintwide_t; template constexpr auto cbrt(const uintwide_t& m) -> uintwide_t; template constexpr auto rootk(const uintwide_t& m, const std::uint_fast8_t k) -> uintwide_t; // NOLINT(readability-avoid-const-params-in-decls) template constexpr auto pow(const uintwide_t& b, const OtherIntegralTypeP& p) -> uintwide_t; template constexpr auto powm(const uintwide_t& b, const OtherIntegralTypeP& p, const OtherIntegralTypeM& m) -> uintwide_t; template constexpr auto gcd(const uintwide_t& a, const uintwide_t& b) -> uintwide_t; template constexpr auto gcd(const UnsignedShortType& u, const UnsignedShortType& v) -> std::enable_if_t<( std::is_integral::value && std::is_unsigned::value), UnsignedShortType>; template constexpr auto lcm(const uintwide_t& a, const uintwide_t& b) -> uintwide_t; template constexpr auto lcm(const UnsignedShortType& a, const UnsignedShortType& b) -> std::enable_if_t<( std::is_integral::value && std::is_unsigned::value), UnsignedShortType>; template constexpr auto divmod(const uintwide_t& a, const uintwide_t& b, std::enable_if_t<((!IsSignedLeft) && (!IsSignedRight)), int>* p_nullparam = nullptr) -> std::pair, uintwide_t>; template constexpr auto divmod(const uintwide_t& a, const uintwide_t& b, std::enable_if_t<(IsSignedLeft || IsSignedRight), int>* p_nullparam = nullptr) -> std::pair, uintwide_t>; template class default_random_engine; template class uniform_int_distribution; template constexpr auto operator==(const uniform_int_distribution& lhs, const uniform_int_distribution& rhs) -> bool; template constexpr auto operator!=(const uniform_int_distribution& lhs, const uniform_int_distribution& rhs) -> bool; template auto miller_rabin(const uintwide_t& n, const unsigned_fast_type number_of_trials, // NOLINT(readability-avoid-const-params-in-decls) DistributionType& distribution, GeneratorType& generator) -> bool; #if (defined(__cpp_lib_to_chars) && (__cpp_lib_to_chars >= 201611L)) template constexpr auto to_chars(char* first, char* last, const uintwide_t& x, int base = static_cast(INT8_C(10))) -> std::to_chars_result; template constexpr auto from_chars(const char* first, const char* last, uintwide_t& x, int base = static_cast(INT8_C(10))) -> std::from_chars_result; #endif #if !defined(WIDE_INTEGER_DISABLE_TO_STRING) template auto to_string(const uintwide_t& x) -> std::string; #endif template::value_type>::digits == std::numeric_limits::digits> const* = nullptr> constexpr auto import_bits(uintwide_t& val, ForwardIterator first, ForwardIterator last, unsigned chunk_size = static_cast(UINT8_C(0)), bool msv_first = true) -> uintwide_t&; template::value_type>::digits == std::numeric_limits::digits)> const* = nullptr> constexpr auto import_bits(uintwide_t& val, ForwardIterator first, ForwardIterator last, unsigned chunk_size = static_cast(UINT8_C(0)), bool msv_first = true) -> uintwide_t&; template::value_type>::digits == std::numeric_limits::digits> const* = nullptr> constexpr auto export_bits(const uintwide_t& val, OutputIterator out, unsigned chunk_size, bool msv_first = true) -> OutputIterator; template::value_type>::digits == std::numeric_limits::digits)> const* = nullptr> constexpr auto export_bits(const uintwide_t& val, OutputIterator out, unsigned chunk_size, bool msv_first = true) -> OutputIterator; #if(__cplusplus >= 201703L) } // namespace math::wide_integer #else } // namespace wide_integer } // namespace math #endif WIDE_INTEGER_NAMESPACE_END namespace std { // Forward declaration of specialization of std::numeric_limits. #if defined(WIDE_INTEGER_NAMESPACE) template WIDE_INTEGER_NUM_LIMITS_CLASS_TYPE numeric_limits>; #else template WIDE_INTEGER_NUM_LIMITS_CLASS_TYPE numeric_limits<::math::wide_integer::uintwide_t>; // NOLINT(cert-dcl58-cpp) #endif } // namespace std WIDE_INTEGER_NAMESPACE_BEGIN #if(__cplusplus >= 201703L) namespace math::wide_integer::detail { #else namespace math { namespace wide_integer { namespace detail { // NOLINT(modernize-concat-nested-namespaces) #endif template class fixed_dynamic_array final : public detail::dynamic_array // NOLINT(cppcoreguidelines-special-member-functions,hicpp-special-member-functions) { private: using base_class_type = detail::dynamic_array; public: static constexpr auto static_size() -> typename base_class_type::size_type { return MySize; } explicit constexpr fixed_dynamic_array(const typename base_class_type::size_type size_in = MySize, const typename base_class_type::value_type& value_in = typename base_class_type::value_type(), const typename base_class_type::allocator_type& alloc_in = typename base_class_type::allocator_type()) : base_class_type(MySize, typename base_class_type::value_type(), alloc_in) { detail::fill_unsafe(base_class_type::begin(), base_class_type::begin() + (detail::min_unsafe)(MySize, static_cast(size_in)), value_in); } constexpr fixed_dynamic_array(const fixed_dynamic_array& other_array) = default; constexpr fixed_dynamic_array(fixed_dynamic_array&& other_array) noexcept = default; constexpr fixed_dynamic_array(std::initializer_list lst) : base_class_type(MySize) { detail::copy_unsafe(lst.begin(), lst.begin() + (detail::min_unsafe)(static_cast(lst.size()), MySize), base_class_type::begin()); } constexpr auto operator=(const fixed_dynamic_array& other_array) -> fixed_dynamic_array& = default; constexpr auto operator=(fixed_dynamic_array&& other_array) noexcept -> fixed_dynamic_array& = default; }; struct allocator_dummy_unsafe { constexpr allocator_dummy_unsafe() = default; }; template class fixed_static_array final : public detail::array_detail::array(MySize)> { private: using base_class_type = detail::array_detail::array(MySize)>; public: using size_type = size_t; using value_type = typename base_class_type::value_type; using allocator_type = allocator_dummy_unsafe; static constexpr auto static_size() -> size_type { return MySize; } constexpr fixed_static_array() = default; explicit constexpr fixed_static_array(const size_type size_in, const value_type& value_in = value_type(), allocator_type alloc_in = allocator_type()) { static_cast(alloc_in); if(size_in < static_size()) { detail::fill_unsafe(base_class_type::begin(), base_class_type::begin() + size_in, value_in); detail::fill_unsafe(base_class_type::begin() + size_in, base_class_type::end(), value_type()); } else { // Exclude this line from code coverage, even though explicit // test cases (search for "result_overshift_is_ok") are known // to cover this line. detail::fill_unsafe(base_class_type::begin(), base_class_type::end(), value_in); } } constexpr fixed_static_array(const fixed_static_array&) = default; constexpr fixed_static_array(fixed_static_array&&) noexcept = default; constexpr fixed_static_array(std::initializer_list lst) { const auto size_to_copy = (detail::min_unsafe)(static_cast(lst.size()), MySize); if(size_to_copy < static_cast(base_class_type::size())) { detail::copy_unsafe(lst.begin(), lst.begin() + size_to_copy, base_class_type::begin()); detail::fill_unsafe(base_class_type::begin() + size_to_copy, base_class_type::end(), static_cast(UINT8_C(0))); } else { detail::copy_unsafe(lst.begin(), lst.begin() + size_to_copy, base_class_type::begin()); } } //constexpr ~fixed_static_array() = default; constexpr auto operator=(const fixed_static_array& other_array) -> fixed_static_array& = default; constexpr auto operator=(fixed_static_array&& other_array) noexcept -> fixed_static_array& = default; constexpr auto operator[](const size_type i) -> typename base_class_type::reference { return base_class_type::operator[](static_cast(i)); } constexpr auto operator[](const size_type i) const -> typename base_class_type::const_reference { return base_class_type::operator[](static_cast(i)); } }; template struct verify_power_of_two_times_granularity_one_sixty_fourth // NOLINT(altera-struct-pack-align) { // List of numbers used to identify the form 2^n times 1...63. static constexpr auto conditional_value = ( verify_power_of_two(Width2 / 1U)>::conditional_value || verify_power_of_two(Width2 / 3U)>::conditional_value || verify_power_of_two(Width2 / 5U)>::conditional_value || verify_power_of_two(Width2 / 7U)>::conditional_value || verify_power_of_two(Width2 / 9U)>::conditional_value || verify_power_of_two(Width2 / 11U)>::conditional_value || verify_power_of_two(Width2 / 13U)>::conditional_value || verify_power_of_two(Width2 / 15U)>::conditional_value || verify_power_of_two(Width2 / 17U)>::conditional_value || verify_power_of_two(Width2 / 19U)>::conditional_value || verify_power_of_two(Width2 / 21U)>::conditional_value || verify_power_of_two(Width2 / 23U)>::conditional_value || verify_power_of_two(Width2 / 25U)>::conditional_value || verify_power_of_two(Width2 / 27U)>::conditional_value || verify_power_of_two(Width2 / 29U)>::conditional_value || verify_power_of_two(Width2 / 31U)>::conditional_value || verify_power_of_two(Width2 / 33U)>::conditional_value || verify_power_of_two(Width2 / 35U)>::conditional_value || verify_power_of_two(Width2 / 37U)>::conditional_value || verify_power_of_two(Width2 / 39U)>::conditional_value || verify_power_of_two(Width2 / 41U)>::conditional_value || verify_power_of_two(Width2 / 43U)>::conditional_value || verify_power_of_two(Width2 / 45U)>::conditional_value || verify_power_of_two(Width2 / 47U)>::conditional_value || verify_power_of_two(Width2 / 49U)>::conditional_value || verify_power_of_two(Width2 / 51U)>::conditional_value || verify_power_of_two(Width2 / 53U)>::conditional_value || verify_power_of_two(Width2 / 55U)>::conditional_value || verify_power_of_two(Width2 / 57U)>::conditional_value || verify_power_of_two(Width2 / 59U)>::conditional_value || verify_power_of_two(Width2 / 61U)>::conditional_value || verify_power_of_two(Width2 / 63U)>::conditional_value); }; template constexpr auto lsb_helper(const UnsignedIntegralType& u) -> unsigned_fast_type; template constexpr auto msb_helper(const UnsignedIntegralType& u) -> unsigned_fast_type; template<> constexpr auto msb_helper(const std::uint32_t& u) -> unsigned_fast_type; template<> constexpr auto msb_helper(const std::uint16_t& u) -> unsigned_fast_type; template<> constexpr auto msb_helper(const std::uint8_t& u) -> unsigned_fast_type; // Use a local implementation of string copy. template constexpr auto strcpy_unsafe(DestinationIterator dst, SourceIterator src) -> DestinationIterator { while((*dst++ = *src++) != '\0') { ; } // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) return dst; } // Use a local implementation of string length. constexpr auto strlen_unsafe(const char* p_str) -> unsigned_fast_type { auto str_len_count = static_cast(UINT8_C(0)); while(*p_str != '\0') { ++p_str; ++str_len_count; } // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic,altera-id-dependent-backward-branch) return str_len_count; } template constexpr auto advance_and_point(InputIterator it, IntegralType n) -> InputIterator { using local_signed_integral_type = std::conditional_t::value, IntegralType, typename detail::uint_type_helper(std::numeric_limits::digits)>::exact_signed_type>; using local_difference_type = typename detail::iterator_detail::iterator_traits::difference_type; return it + static_cast(static_cast(n)); } template(std::numeric_limits::digits * 2)>::exact_unsigned_type> constexpr auto make_lo(const UnsignedLargeType& u) -> UnsignedShortType { // From an unsigned integral input parameter of type UnsignedLargeType, // extract the low part of it. The type of the extracted // low part is UnsignedShortType, which has half the width of UnsignedLargeType. using local_ushort_type = UnsignedShortType; using local_ularge_type = UnsignedLargeType; // Compile-time checks. #if defined(WIDE_INTEGER_HAS_LIMB_TYPE_UINT64) static_assert(((sizeof(local_ushort_type) * 2U) == sizeof(local_ularge_type)), "Error: Please check the characteristics of the template parameters UnsignedShortType and UnsignedLargeType"); #else static_assert(( ( std::numeric_limits::is_integer) && ( std::numeric_limits::is_integer) && (!std::numeric_limits::is_signed) && (!std::numeric_limits::is_signed) && ((sizeof(local_ushort_type) * 2U) == sizeof(local_ularge_type))), "Error: Please check the characteristics of the template parameters UnsignedShortType and UnsignedLargeType"); #endif return static_cast(u); } template(std::numeric_limits::digits * 2)>::exact_unsigned_type> constexpr auto make_hi(const UnsignedLargeType& u) -> UnsignedShortType { // From an unsigned integral input parameter of type UnsignedLargeType, // extract the high part of it. The type of the extracted // high part is UnsignedShortType, which has half the width of UnsignedLargeType. using local_ushort_type = UnsignedShortType; using local_ularge_type = UnsignedLargeType; // Compile-time checks. #if defined(WIDE_INTEGER_HAS_LIMB_TYPE_UINT64) static_assert(((sizeof(local_ushort_type) * 2U) == sizeof(local_ularge_type)), "Error: Please check the characteristics of the template parameters UnsignedShortType and UnsignedLargeType"); #else static_assert(( ( std::numeric_limits::is_integer) && ( std::numeric_limits::is_integer) && (!std::numeric_limits::is_signed) && (!std::numeric_limits::is_signed) && ((sizeof(local_ushort_type) * 2U) == sizeof(local_ularge_type))), "Error: Please check the characteristics of the template parameters UnsignedShortType and UnsignedLargeType"); #endif return static_cast(u >> static_cast(std::numeric_limits::digits)); } template(std::numeric_limits::digits * 2)>::exact_unsigned_type> constexpr auto make_large(const UnsignedShortType& lo, const UnsignedShortType& hi) -> UnsignedLargeType { // Create a composite unsigned integral value having type UnsignedLargeType. // Two constituents are used having type UnsignedShortType, whereby the // width of UnsignedShortType is half the width of UnsignedLargeType. using local_ushort_type = UnsignedShortType; using local_ularge_type = UnsignedLargeType; // Compile-time checks. #if defined(WIDE_INTEGER_HAS_LIMB_TYPE_UINT64) static_assert(((sizeof(local_ushort_type) * 2U) == sizeof(local_ularge_type)), "Error: Please check the characteristics of the template parameters UnsignedShortType and UnsignedLargeType"); #else static_assert(( ( std::numeric_limits::is_integer) && ( std::numeric_limits::is_integer) && (!std::numeric_limits::is_signed) && (!std::numeric_limits::is_signed) && ((sizeof(local_ushort_type) * 2U) == sizeof(local_ularge_type))), "Error: Please check the characteristics of the template parameters UnsignedShortType and UnsignedLargeType"); #endif return static_cast ( static_cast ( static_cast(hi) << static_cast(std::numeric_limits::digits) ) | lo ); } template constexpr auto negate(UnsignedIntegralType u) -> std::enable_if_t<( std::is_integral::value && std::is_unsigned::value), UnsignedIntegralType> { using local_unsigned_integral_type = UnsignedIntegralType; return static_cast ( static_cast(~u) + static_cast(UINT8_C(1)) ); } template constexpr auto negate(SignedIntegralType n) -> std::enable_if_t<( std::is_integral::value && std::is_signed::value), SignedIntegralType> { using local_signed_integral_type = SignedIntegralType; using local_unsigned_integral_type = typename detail::uint_type_helper(std::numeric_limits::digits + 1)>::exact_unsigned_type; return static_cast ( negate(static_cast(n)) ); } #if !defined(WIDE_INTEGER_DISABLE_FLOAT_INTEROP) template class native_float_parts final { public: constexpr native_float_parts() = delete; // Emphasize: This template class can be used with native floating-point // types like float, double and long double. Note: For long double, // you need to verify that the mantissa fits in unsigned long long. explicit constexpr native_float_parts(const FloatingPointType f) { using native_float_type = FloatingPointType; static_assert(std::numeric_limits::digits <= std::numeric_limits::digits, // NOLINT(google-runtime-int) "Error: The width of the mantissa does not fit in unsigned long long"); const auto ff = static_cast ( (f < static_cast(0.0F)) ? static_cast(-f) : f ); if(ff < (std::numeric_limits::min)()) { return; } using my_own::frexp; // Get the fraction and base-2 exponent. auto man = static_cast(frexp(f, &my_exponent_part)); auto n2 = static_cast(UINT8_C(0)); for(auto i = static_cast(UINT8_C(0)); i < static_cast(std::numeric_limits::digits); ++i) { // Extract the mantissa of the floating-point type in base-2 // (one bit at a time) and store it in an unsigned long long. man *= static_cast(INT8_C(2)); n2 = static_cast(man); man -= static_cast(n2); if(n2 != static_cast(UINT8_C(0))) { my_mantissa_part |= static_cast(UINT8_C(1)); } if(i < static_cast(static_cast(std::numeric_limits::digits - static_cast(INT8_C(1))))) { my_mantissa_part <<= static_cast(UINT8_C(1)); } } // Ensure that the value is normalized and adjust the exponent. my_mantissa_part |= static_cast(1ULL << static_cast(std::numeric_limits::digits - 1)); // NOLINT(google-runtime-int) my_exponent_part -= static_cast(INT8_C(1)); } constexpr native_float_parts(const native_float_parts& other) = default; constexpr native_float_parts(native_float_parts&& other) noexcept = default; ~native_float_parts() = default; constexpr auto operator=(const native_float_parts& other) noexcept -> native_float_parts& // NOLINT(cert-oop54-cpp) { if(this != &other) { my_mantissa_part = other.my_mantissa_part; my_exponent_part = other.my_exponent_part; } return *this; } constexpr auto operator=(native_float_parts&& other) noexcept -> native_float_parts& { my_mantissa_part = other.my_mantissa_part; my_exponent_part = other.my_exponent_part; return *this; } WIDE_INTEGER_NODISCARD constexpr auto get_mantissa() const noexcept -> unsigned long long { return my_mantissa_part; } // NOLINT(google-runtime-int) WIDE_INTEGER_NODISCARD constexpr auto get_exponent() const noexcept -> int { return my_exponent_part; } private: unsigned long long my_mantissa_part { }; // NOLINT(readability-identifier-naming,google-runtime-int) int my_exponent_part { }; // NOLINT(readability-identifier-naming) }; #endif #if(__cplusplus >= 201703L) } // namespace math::wide_integer::detail #else } // namespace detail } // namespace wide_integer } // namespace math #endif #if(__cplusplus >= 201703L) namespace math::wide_integer { #else namespace math { namespace wide_integer { // NOLINT(modernize-concat-nested-namespaces) #endif template class uintwide_t // NOLINT(cppcoreguidelines-special-member-functions,hicpp-special-member-functions) { public: template friend class uintwide_t; // Class-local type definitions. using limb_type = LimbType; using double_limb_type = typename detail::uint_type_helper(static_cast(std::numeric_limits::digits * static_cast(INT8_C(2))))>::exact_unsigned_type; // Legacy ularge and ushort types. These are no longer used // in the class, but provided for legacy compatibility. using ushort_type = limb_type; using ularge_type = double_limb_type; // More compile-time checks. #if defined(WIDE_INTEGER_HAS_LIMB_TYPE_UINT64) static_assert(((sizeof(limb_type) * 2U) == sizeof(double_limb_type)), "Error: Please check the characteristics of the template parameters UnsignedShortType and UnsignedLargeType"); #else static_assert(( ( std::numeric_limits::is_integer) && ( std::numeric_limits::is_integer) && (!std::numeric_limits::is_signed) && (!std::numeric_limits::is_signed) && ((sizeof(limb_type) * 2U) == sizeof(double_limb_type))), "Error: Please check the characteristics of the template parameters UnsignedShortType and UnsignedLargeType"); #endif // Helper constants for the digit characteristics. static constexpr size_t my_width2 = Width2; // The number of limbs. static constexpr size_t number_of_limbs = static_cast ( Width2 / static_cast(std::numeric_limits::digits) ); static constexpr size_t number_of_limbs_karatsuba_threshold = static_cast ( static_cast ( static_cast(UINT8_C(128)) + static_cast(UINT8_C(1)) ) ); // Verify that the Width2 template parameter (mirrored with my_width2): // * Is equal to 2^n times 1...63. // * And that there are at least 16, 24 or 32 binary digits, or more. // * And that the number of binary digits is an exact multiple of the number of limbs. static_assert( detail::verify_power_of_two_times_granularity_one_sixty_fourth::conditional_value && (my_width2 >= static_cast(UINT8_C(16))) && (my_width2 == static_cast(number_of_limbs * static_cast(std::numeric_limits::digits))), "Error: Width2 must be 2^n times 1...63 (with n >= 3), while being 16, 24, 32 or larger, and exactly divisible by limb count"); // The type of the internal data representation. using representation_type = std::conditional_t ::value, detail::fixed_static_array , detail::fixed_dynamic_array::value, std::allocator, AllocatorType>>::template rebind_alloc>>; // The iterator types of the internal data representation. using iterator = typename representation_type::iterator; using const_iterator = typename representation_type::const_iterator; using reverse_iterator = typename representation_type::reverse_iterator; using const_reverse_iterator = typename representation_type::const_reverse_iterator; // Define a class-local type that has double the width of *this. using double_width_type = uintwide_t(Width2 * static_cast(UINT8_C(2))), limb_type, AllocatorType, IsSigned>; // Default constructor. constexpr uintwide_t() = default; // Constructors from built-in unsigned integral types that // are less wide than limb_type or exactly as wide as limb_type. template constexpr uintwide_t(const UnsignedIntegralType v, // NOLINT(google-explicit-constructor,hicpp-explicit-conversions) std::enable_if_t<( std::is_integral ::value && std::is_unsigned ::value && (std::numeric_limits::digits <= std::numeric_limits::digits))>* = nullptr) // NOLINT(hicpp-named-parameter,readability-named-parameter) { values.front() = v; } // Constructors from built-in unsigned integral types that // are wider than limb_type, and do not have exactly the // same width as limb_type. template constexpr uintwide_t(const UnsignedIntegralType v, // NOLINT(google-explicit-constructor,hicpp-explicit-conversions) std::enable_if_t<( std::is_integral ::value && std::is_unsigned ::value && (std::numeric_limits::digits > std::numeric_limits::digits))>* p_nullparam = nullptr) { static_cast(p_nullparam == nullptr); auto u_it = values.begin(); // NOLINT(llvm-qualified-auto,readability-qualified-auto) auto vr = v; using local_unsigned_integral_type = UnsignedIntegralType; while(vr != static_cast(UINT8_C(0))) // NOLINT(altera-id-dependent-backward-branch) { if(u_it != values.end()) { *u_it = static_cast(vr); ++u_it; vr = static_cast(vr >> static_cast(std::numeric_limits::digits)); } else { break; } } detail::fill_unsafe(u_it, values.end(), static_cast(UINT8_C(0))); } // Constructors from built-in signed integral types. template constexpr uintwide_t(const SignedIntegralType v, // NOLINT(google-explicit-constructor,hicpp-explicit-conversions) std::enable_if_t<( std::is_integral::value && std::is_signed ::value)>* p_nullparam = nullptr) : values(number_of_limbs) { static_cast(p_nullparam == nullptr); using local_signed_integral_type = SignedIntegralType; using local_unsigned_integral_type = typename detail::uint_type_helper(std::numeric_limits::digits + 1)>::exact_unsigned_type; const auto v_is_neg = (v < static_cast(0)); const local_unsigned_integral_type u = ((!v_is_neg) ? static_cast(v) : static_cast(detail::negate(v))); operator=(uintwide_t(u)); if(v_is_neg) { negate(); } } #if !defined(WIDE_INTEGER_DISABLE_FLOAT_INTEROP) template::value)> const* = nullptr> constexpr uintwide_t(const FloatingPointType f) // NOLINT(google-explicit-constructor,hicpp-explicit-conversions) { using local_builtin_float_type = FloatingPointType; using detail::my_own::isfinite; if(!(isfinite)(f)) { operator=(static_cast(UINT8_C(0))); } else { const auto f_is_neg = (f < static_cast(0.0F)); const auto a = static_cast ( (!f_is_neg) ? f : static_cast(-f) ); const auto a_is_zero = (a < static_cast(1.0F)); if(!a_is_zero) { const detail::native_float_parts ld_parts(a); // Create a decwide_t from the fractional part of the // mantissa expressed as an unsigned long long. *this = uintwide_t(ld_parts.get_mantissa()); // Scale the unsigned long long representation to the fractional // part of the long double and multiply with the base-2 exponent. const auto p2 = static_cast ( ld_parts.get_exponent() - static_cast(std::numeric_limits::digits - static_cast(INT8_C(1))) ); if (p2 < static_cast(INT8_C(0))) { *this >>= static_cast(-p2); } else if(p2 == static_cast(INT8_C(0))) { ; } else { *this <<= static_cast( p2); } if(f_is_neg) { negate(); } } else { operator=(static_cast(UINT8_C(0))); } } } #endif // Copy constructor. #if !defined(WIDE_INTEGER_DISABLE_TRIVIAL_COPY_AND_STD_LAYOUT_CHECKS) constexpr uintwide_t(const uintwide_t& other) = default; #else constexpr uintwide_t(const uintwide_t& other) : values(other.values) { } #endif // Copy-like constructor from the other signed-ness type. template const* = nullptr> constexpr uintwide_t(const uintwide_t& other) // NOLINT(google-explicit-constructor,hicpp-explicit-conversions) : values(other.values) { } // Copy-like constructor from the another type having width that is wider // (but has the same limb type) and possibly a different signed-ness. template const* = nullptr> explicit constexpr uintwide_t(const uintwide_t& v) { using other_wide_integer_type = uintwide_t; const auto v_is_neg = (other_wide_integer_type::is_neg(v)); constexpr auto sz = static_cast(number_of_limbs); if(!v_is_neg) { detail::copy_unsafe(v.crepresentation().cbegin(), detail::advance_and_point(v.crepresentation().cbegin(), sz), values.begin()); } else { const other_wide_integer_type uv(-v); detail::copy_unsafe(uv.crepresentation().cbegin(), detail::advance_and_point(uv.crepresentation().cbegin(), sz), values.begin()); negate(); // LCOV_EXCL_LINE } } // Copy-like constructor from the another type having width that is less wide // (but has the same limb type) and possibly a different signed-ness. template OtherWidth2)> const* = nullptr> explicit constexpr uintwide_t(const uintwide_t& v) { using other_wide_integer_type = uintwide_t; constexpr auto sz = static_cast(other_wide_integer_type::number_of_limbs); if(!other_wide_integer_type::is_neg(v)) { detail::copy_unsafe(v.crepresentation().cbegin(), detail::advance_and_point(v.crepresentation().cbegin(), sz), values.begin()); detail::fill_unsafe(detail::advance_and_point(values.begin(), sz), values.end(), static_cast(UINT8_C(0))); } else { const other_wide_integer_type uv(-v); detail::copy_unsafe(uv.crepresentation().cbegin(), detail::advance_and_point(uv.crepresentation().cbegin(), sz), values.begin()); detail::fill_unsafe(detail::advance_and_point(values.begin(), sz), values.end(), static_cast(UINT8_C(0))); negate(); } } // Constructor from a constant character string. constexpr uintwide_t(const char* str_input) // NOLINT(google-explicit-constructor,hicpp-explicit-conversions) : values { static_cast(number_of_limbs), static_cast(UINT8_C(0)), typename representation_type::allocator_type() } { if(!rd_string(str_input, (std::numeric_limits::max)(), 0)) { static_cast(operator=((std::numeric_limits::max)())); } } // Move constructor. constexpr uintwide_t(uintwide_t&&) noexcept = default; // LCOV_EXCL_LINE // Move-like constructor from the other signed-ness type. // This constructor is non-explicit because it is a trivial conversion. template const* = nullptr> constexpr uintwide_t(uintwide_t&& other) // NOLINT(google-explicit-constructor,hicpp-explicit-conversions) : values(static_cast(other.values)) { } // Assignment operator. constexpr auto operator=(const uintwide_t&) -> uintwide_t& = default; // LCOV_EXCL_LINE // Assignment operator from the other signed-ness type. template const* = nullptr> constexpr auto operator=(const uintwide_t& other) -> uintwide_t& { values = other.values; return *this; } // Trivial move assignment operator. constexpr auto operator=(uintwide_t&& other) noexcept -> uintwide_t& = default; // LCOV_EXCL_LINE // Trivial move assignment operator from the other signed-ness type. template const* = nullptr> constexpr auto operator=(uintwide_t&& other) -> uintwide_t& { values = static_cast(other.values); return *this; } #if !defined(WIDE_INTEGER_DISABLE_FLOAT_INTEROP) explicit constexpr operator long double() const { return extract_builtin_floating_point_type(); } explicit constexpr operator double () const { return extract_builtin_floating_point_type (); } explicit constexpr operator float () const { return extract_builtin_floating_point_type (); } #endif template::value>> explicit constexpr operator IntegralType() const { using local_integral_type = IntegralType; return ( (!is_neg(*this)) ? extract_builtin_integral_type() : detail::negate((-*this).template extract_builtin_integral_type()) ); } // Cast operator to built-in Boolean type. explicit constexpr operator bool() const { return (!is_zero()); } // Cast operator that casts to a uintwide_t possibly having a different width // and/or possibly having a different signed-ness, but having the same limb type. template constexpr operator uintwide_t() const // NOLINT(hicpp-explicit-conversions,google-explicit-constructor) { const auto this_is_neg = is_neg(*this); using other_wide_integer_type = uintwide_t; constexpr auto sz = static_cast ( (Width2 < OtherWidth2) ? static_cast(number_of_limbs) : static_cast(other_wide_integer_type::number_of_limbs) ); other_wide_integer_type other { }; if(!this_is_neg) { detail::copy_unsafe(crepresentation().cbegin(), detail::advance_and_point(crepresentation().cbegin(), sz), other.values.begin()); } else { other_wide_integer_type uv(*this); uv.negate(); detail::copy_unsafe(uv.crepresentation().cbegin(), detail::advance_and_point(uv.crepresentation().cbegin(), sz), other.values.begin()); other.negate(); } return other; } // Provide a user interface to the internal data representation. constexpr auto representation() -> representation_type& { return values; } WIDE_INTEGER_NODISCARD constexpr auto representation() const -> const representation_type& { return values; } WIDE_INTEGER_NODISCARD constexpr auto crepresentation() const -> const representation_type& { return values; } // Unary operators plus and minus. constexpr auto operator+() const -> const uintwide_t& { return *this; } constexpr auto operator-() const -> uintwide_t { uintwide_t tmp(*this); tmp.negate(); return tmp; } constexpr auto operator+=(const uintwide_t& other) -> uintwide_t& { if(this == &other) { // Unary addition function. const auto carry = eval_add_n(values.begin(), // LCOV_EXCL_LINE values.cbegin(), other.values.cbegin(), static_cast(number_of_limbs), static_cast(UINT8_C(0))); static_cast(carry); } else { // Unary addition function. const auto carry = eval_add_n(values.begin(), values.cbegin(), other.values.cbegin(), static_cast(number_of_limbs), static_cast(UINT8_C(0))); static_cast(carry); } return *this; } constexpr auto operator-=(const uintwide_t& other) -> uintwide_t& { if(this == &other) { detail::fill_unsafe(values.begin(), values.end(), static_cast(UINT8_C(0))); } else { // Unary subtraction function. const auto has_borrow = eval_subtract_n(values.begin(), values.cbegin(), other.values.cbegin(), number_of_limbs, false); static_cast(has_borrow); } return *this; } constexpr auto operator*=(const uintwide_t& other) -> uintwide_t& { if(this == &other) { eval_mul_unary(*this, uintwide_t(other)); // NOLINT(performance-unnecessary-copy-initialization) } else { eval_mul_unary(*this, other); } return *this; } constexpr auto mul_by_limb(const limb_type v) -> uintwide_t& { if(v == static_cast(UINT8_C(0))) { detail::fill_unsafe(values.begin(), values.end(), static_cast(UINT8_C(0))); } else if(v > static_cast(UINT8_C(1))) { static_cast(eval_multiply_1d(values.begin(), values.cbegin(), v, number_of_limbs)); } return *this; } constexpr auto operator/=(const uintwide_t& other) -> uintwide_t& { if(this == &other) { values.front() = static_cast(UINT8_C(1)); detail::fill_unsafe(detail::advance_and_point(values.begin(), 1U), values.end(), static_cast(UINT8_C(0))); // LCOV_EXCL_LINE } else if(other.is_zero()) { static_cast(operator=(limits_helper_max())); } else { // Unary division function. const auto numer_was_neg = is_neg(*this); const auto denom_was_neg = is_neg(other); if(numer_was_neg || denom_was_neg) { using local_unsigned_wide_type = uintwide_t; local_unsigned_wide_type a(*this); local_unsigned_wide_type b(other); if(numer_was_neg) { a.negate(); } if(denom_was_neg) { b.negate(); } a.eval_divide_knuth(b); if(numer_was_neg != denom_was_neg) { a.negate(); } values = a.values; } else { eval_divide_knuth(other); } } return *this; } constexpr auto operator%=(const uintwide_t& other) -> uintwide_t& { if(this == &other) { detail::fill_unsafe(values.begin(), values.end(), static_cast(UINT8_C(0))); // LCOV_EXCL_LINE } else { // Unary modulus function. const auto numer_was_neg = is_neg(*this); const auto denom_was_neg = is_neg(other); if(numer_was_neg || denom_was_neg) { using local_unsigned_wide_type = uintwide_t; local_unsigned_wide_type a(*this); local_unsigned_wide_type b(other); if(numer_was_neg) { a.negate(); } if(denom_was_neg) { b.negate(); } local_unsigned_wide_type remainder_unsigned { }; a.eval_divide_knuth(b, &remainder_unsigned); // The sign of the remainder follows the sign of the denominator. if(numer_was_neg) { remainder_unsigned.negate(); } values = remainder_unsigned.values; } else { uintwide_t remainder { }; eval_divide_knuth(other, &remainder); values = remainder.values; } } return *this; } // Operators pre-increment and pre-decrement. constexpr auto operator++() -> uintwide_t& { preincrement(); return *this; } constexpr auto operator--() -> uintwide_t& { predecrement(); return *this; } // Operators post-increment and post-decrement. constexpr auto operator++(int) -> uintwide_t { const uintwide_t w(*this); preincrement(); return w; } constexpr auto operator--(int) -> uintwide_t { const uintwide_t w(*this); predecrement(); return w; } constexpr auto operator~() -> uintwide_t& { // Perform bitwise NOT. bitwise_not(); return *this; } constexpr auto operator|=(const uintwide_t& other) -> uintwide_t& // LCOV_EXCL_LINE { if(this != &other) // LCOV_EXCL_LINE { auto itr_b = other.values.cbegin(); // NOLINT(llvm-qualified-auto,readability-qualified-auto) // Perform bitwise OR. for(auto itr_a = values.begin(); itr_a != values.end(); ++itr_a, ++itr_b) // NOLINT(altera-id-dependent-backward-branch,llvm-qualified-auto,readability-qualified-auto) { *itr_a = static_cast(*itr_a | *itr_b); } } return *this; // LCOV_EXCL_LINE } constexpr auto operator^=(const uintwide_t& other) -> uintwide_t& // LCOV_EXCL_LINE { if(this == &other) // LCOV_EXCL_LINE { detail::fill_unsafe(values.begin(), values.end(), static_cast(UINT8_C(0))); // LCOV_EXCL_LINE } else { auto itr_b = other.values.cbegin(); // NOLINT(llvm-qualified-auto,readability-qualified-auto) // Perform bitwise XOR. for(auto itr_a = values.begin(); itr_a != values.end(); ++itr_a, ++itr_b) // NOLINT(altera-id-dependent-backward-branch,llvm-qualified-auto,readability-qualified-auto) { *itr_a = static_cast(*itr_a ^ *itr_b); } } return *this; // LCOV_EXCL_LINE } constexpr auto operator&=(const uintwide_t& other) -> uintwide_t& { if(this != &other) // LCOV_EXCL_LINE { auto itr_b = other.values.cbegin(); // NOLINT(llvm-qualified-auto,readability-qualified-auto) // Perform bitwise AND. for(auto itr_a = values.begin(); itr_a != values.end(); ++itr_a, ++itr_b) // NOLINT(altera-id-dependent-backward-branch,llvm-qualified-auto,readability-qualified-auto) { *itr_a = static_cast(*itr_a & *itr_b); } } return *this; } template constexpr auto operator<<=(const SignedIntegralType n) -> std::enable_if_t<( std::is_integral::value && std::is_signed ::value), uintwide_t>& { // Implement left-shift operator for signed integral argument. if(n < static_cast(0)) { using local_unsigned_type = typename detail::uint_type_helper(std::numeric_limits::digits + 1)>::exact_unsigned_type; operator>>=(static_cast(detail::negate(n))); } else if(n > static_cast(0)) { if(exceeds_width(n)) { // Exclude this line from code coverage, even though explicit // test cases (search for "result_overshift_is_ok") are known // to cover this line. detail::fill_unsafe(values.begin(), values.end(), static_cast(UINT8_C(0))); // LCOV_EXCL_LINE } else { shl(n); } } return *this; } template constexpr auto operator<<=(const UnsignedIntegralType n) -> std::enable_if_t<( std::is_integral::value && (!std::is_signed ::value)), uintwide_t>& { // Implement left-shift operator for unsigned integral argument. if(n != static_cast(0)) { if(exceeds_width(n)) { // Exclude this line from code coverage, even though explicit // test cases (search for "result_overshift_is_ok") are known // to cover this line. detail::fill_unsafe(values.begin(), values.end(), static_cast(UINT8_C(0))); // LCOV_EXCL_LINE } else { shl(n); } } return *this; } template constexpr auto operator>>=(const SignedIntegralType n) -> std::enable_if_t<( std::is_integral::value && std::is_signed ::value), uintwide_t>& { // Implement right-shift operator for signed integral argument. if(n < static_cast(0)) { using local_unsigned_type = typename detail::uint_type_helper(std::numeric_limits::digits + 1)>::exact_unsigned_type; operator<<=(static_cast(detail::negate(n))); } else if(n > static_cast(0)) { if(exceeds_width(n)) { // Fill with either 0's or 1's. Note also the implementation-defined // behavior of excessive right-shift of negative value. // Exclude this line from code coverage, even though explicit // test cases (search for "result_overshift_is_ok") are known // to cover this line. detail::fill_unsafe(values.begin(), values.end(), right_shift_fill_value()); // LCOV_EXCL_LINE } else { shr(n); } } return *this; } template constexpr auto operator>>=(const UnsignedIntegralType n) -> std::enable_if_t<( std::is_integral::value && (!std::is_signed ::value)), uintwide_t>& { // Implement right-shift operator for unsigned integral argument. if(n != static_cast(0)) { if(exceeds_width(n)) { // Fill with either 0's or 1's. Note also the implementation-defined // behavior of excessive right-shift of negative value. // Exclude this line from code coverage, even though explicit // test cases (search for "result_overshift_is_ok") are known // to cover this line. detail::fill_unsafe(values.begin(), values.end(), right_shift_fill_value()); } else { shr(n); } } return *this; } // Helper functions for supporting std::numeric_limits<>. template static constexpr auto limits_helper_max() -> std::enable_if_t<(!RePhraseIsSigned), uintwide_t> { uintwide_t result_max { }; detail::fill_unsafe(result_max.values.begin(), result_max.values.end(), (std::numeric_limits::max)()); return result_max; } template static constexpr auto limits_helper_max() -> std::enable_if_t { uintwide_t result_max { }; detail::fill_unsafe(result_max.values.begin(), result_max.values.end(), (std::numeric_limits::max)()); constexpr auto high_bit_limb = static_cast ( static_cast(UINT8_C(1)) << static_cast(std::numeric_limits::digits - static_cast(INT8_C(1))) ); result_max.values.back() ^= high_bit_limb; return result_max; } template static constexpr auto limits_helper_min() -> std::enable_if_t<(!RePhraseIsSigned), uintwide_t> { return uintwide_t { }; } template static constexpr auto limits_helper_min() -> std::enable_if_t { uintwide_t result_min { }; constexpr auto high_bit_limb = static_cast ( static_cast(UINT8_C(1)) << static_cast(std::numeric_limits::digits - static_cast(INT8_C(1))) ); result_min.values.back() |= high_bit_limb; return result_min; } // Write string function. template constexpr auto wr_string( OutputStrIterator str_result, // NOLINT(readability-function-cognitive-complexity) const std::uint_fast8_t base_rep = static_cast(UINT8_C(0x10)), const bool show_base = true, const bool show_pos = false, const bool is_uppercase = true, unsigned_fast_type field_width = static_cast(UINT8_C(0)), const char fill_char_str = '0') const -> bool { auto wr_string_is_ok = true; if(base_rep == static_cast(UINT8_C(8))) { uintwide_t t(*this); const auto mask = static_cast(static_cast(0x7U)); using string_storage_oct_type = std::conditional_t (UINT32_C(2048)), detail::fixed_static_array , detail::fixed_dynamic_array::value, std::allocator, AllocatorType>>::template rebind_alloc>>; static_assert(string_storage_oct_type::static_size() > unsigned_fast_type { UINT8_C(1) }, "Error: String storage length must be greater than one"); string_storage_oct_type str_temp { }; // LCOV_EXCL_LINE signed_fast_type pos { static_cast ( string_storage_oct_type::static_size() - static_cast(UINT8_C(1)) // LCOV_EXCL_LINE ) }; if(t.is_zero()) { --pos; str_temp[static_cast(pos)] = '0'; } else { while(!t.is_zero() && (pos > signed_fast_type { UINT8_C(0) })) // NOLINT(altera-id-dependent-backward-branch) { auto c = static_cast(*t.values.cbegin() & mask); if(c <= static_cast(INT8_C(8))) { c = static_cast(c + static_cast(INT8_C(0x30))); } --pos; str_temp[static_cast(pos)] = c; t >>= static_cast(UINT8_C(3)); } } if(show_base && (pos > signed_fast_type { UINT8_C(0) })) { --pos; str_temp[static_cast(pos)] = '0'; } if(show_pos && (pos > signed_fast_type { UINT8_C(0) })) { --pos; str_temp[static_cast(pos)] = '+'; } if(field_width != static_cast(UINT8_C(0))) { field_width = (detail::min_unsafe)(field_width, static_cast(str_temp.size() - UINT8_C(1))); // LCOV_EXCL_LINE while(static_cast(pos) > static_cast((str_temp.size() - UINT8_C(1)) - static_cast(field_width))) // NOLINT(altera-id-dependent-backward-branch) { --pos; str_temp[static_cast(pos)] = fill_char_str; } } str_temp[static_cast(str_temp.size() - static_cast(UINT8_C(1)))] = '\0'; detail::strcpy_unsafe(str_result, str_temp.data() + pos); } else if(base_rep == static_cast(UINT8_C(10))) { uintwide_t t(*this); const auto str_has_neg_sign = is_neg(t); if(str_has_neg_sign) { t.negate(); } using string_storage_dec_type = std::conditional_t (UINT32_C(2048)), detail::fixed_static_array , detail::fixed_dynamic_array::value, std::allocator, AllocatorType>>::template rebind_alloc>>; static_assert(string_storage_dec_type::static_size() > unsigned_fast_type { UINT8_C(1) }, "Error: String storage length must be greater than one"); string_storage_dec_type str_temp { }; // LCOV_EXCL_LINE signed_fast_type pos { static_cast ( string_storage_dec_type::static_size() - static_cast(UINT8_C(1)) // LCOV_EXCL_LINE ) }; if(t.is_zero()) { --pos; str_temp[static_cast(pos)] = '0'; } else { while(!t.is_zero() && (pos > signed_fast_type { UINT8_C(0) })) { const uintwide_t tmp(t); t.eval_divide_by_single_limb(static_cast(UINT8_C(10)), 0U, nullptr); --pos; str_temp[static_cast(pos)] = static_cast ( static_cast ( tmp - (uintwide_t(t).mul_by_limb(static_cast(UINT8_C(10)))) ) + static_cast(UINT8_C(0x30)) ); } } if(pos > signed_fast_type { UINT8_C(0) }) { if(show_pos && (!str_has_neg_sign)) { --pos; str_temp[static_cast(pos)] = '+'; } else if(str_has_neg_sign) { --pos; str_temp[static_cast(pos)] = '-'; } } if(field_width != static_cast(UINT8_C(0))) { field_width = (detail::min_unsafe)(field_width, static_cast(str_temp.size() - size_t { UINT8_C(1) })); // LCOV_EXCL_LINE while(static_cast(pos) > static_cast((str_temp.size() - size_t { UINT8_C(1) }) - static_cast(field_width))) // NOLINT(altera-id-dependent-backward-branch) { --pos; str_temp[static_cast(pos)] = fill_char_str; } } str_temp[static_cast(str_temp.size() - size_t { UINT8_C(1) })] = '\0'; detail::strcpy_unsafe(str_result, str_temp.data() + pos); } else if(base_rep == static_cast(UINT8_C(16))) { uintwide_t t(*this); using string_storage_hex_type = std::conditional_t (UINT32_C(2048)), detail::fixed_static_array , detail::fixed_dynamic_array::value, std::allocator, AllocatorType>>::template rebind_alloc>>; static_assert(string_storage_hex_type::static_size() > unsigned_fast_type { UINT8_C(1) }, "Error: String storage length must be greater than one"); string_storage_hex_type str_temp { }; // LCOV_EXCL_LINE signed_fast_type pos { static_cast ( string_storage_hex_type::static_size() - size_t { UINT8_C(1) } // LCOV_EXCL_LINE ) }; if(t.is_zero()) { --pos; str_temp[static_cast(pos)] = '0'; } else { const auto dst = extract_hex_digits ( t, &str_temp[static_cast(pos)], is_uppercase ); pos -= static_cast(dst); } if(show_base && (pos > signed_fast_type { UINT8_C(1) })) { --pos; str_temp[static_cast(pos)] = (is_uppercase ? 'X' : 'x'); --pos; str_temp[static_cast(pos)] = '0'; } if(show_pos && (pos > signed_fast_type { UINT8_C(0) })) { --pos; str_temp[static_cast(pos)] = '+'; } if(field_width != static_cast(UINT8_C(0))) { field_width = (detail::min_unsafe)(field_width, static_cast(str_temp.size() - size_t { UINT8_C(1) })); // LCOV_EXCL_LINE while(static_cast(pos) > static_cast((str_temp.size() - size_t { UINT8_C(1) }) - static_cast(field_width))) // NOLINT(altera-id-dependent-backward-branch) { --pos; str_temp[static_cast(pos)] = fill_char_str; } } str_temp[static_cast(str_temp.size() - static_cast(UINT8_C(1)))] = '\0'; detail::strcpy_unsafe(str_result, str_temp.data() + pos); } else { wr_string_is_ok = false; } return wr_string_is_ok; } template const* = nullptr> WIDE_INTEGER_NODISCARD constexpr auto compare(const uintwide_t& other) const -> std::int_fast8_t { return compare_ranges(values.cbegin(), other.values.cbegin(), uintwide_t::number_of_limbs); } template const* = nullptr> WIDE_INTEGER_NODISCARD constexpr auto compare(const uintwide_t& other) const -> std::int_fast8_t { auto n_result = std::int_fast8_t { }; const auto other_is_neg = is_neg(other); const auto my_is_neg = is_neg(*this); if(my_is_neg && (!other_is_neg)) { n_result = static_cast(INT8_C(-1)); } else if((!my_is_neg) && other_is_neg) { n_result = static_cast(INT8_C(1)); } else { n_result = compare_ranges(values.cbegin(), other.values.cbegin(), uintwide_t::number_of_limbs); } return n_result; } // What seems to be an optimization or parsing error prevents // getting any LCOV hits in the negate() subroutine, even though // this is known to be used in the coverage tests. // LCOV_EXCL_START constexpr auto negate() -> void { bitwise_not(); preincrement(); } // LCOV_EXCL_STOP constexpr auto eval_divide_by_single_limb(const limb_type short_denominator, const unsigned_fast_type u_offset, uintwide_t* remainder) -> void { // The denominator has one single limb. // Use a one-dimensional division algorithm. auto long_numerator = double_limb_type { }; auto hi_part = static_cast(UINT8_C(0)); { reverse_iterator ri { detail::advance_and_point ( values.begin(), static_cast(number_of_limbs - static_cast(u_offset)) ) }; for( ; ri != values.rend(); ++ri) // NOLINT(altera-id-dependent-backward-branch) { long_numerator = static_cast ( *ri + static_cast ( static_cast ( long_numerator - static_cast(static_cast(short_denominator) * hi_part) ) << static_cast(std::numeric_limits::digits) ) ); *ri = detail::make_lo(static_cast(long_numerator / short_denominator)); hi_part = *ri; } } if(remainder != nullptr) { long_numerator = static_cast ( static_cast(*values.cbegin()) + static_cast ( static_cast ( long_numerator - static_cast(static_cast(short_denominator) * hi_part) ) << static_cast(std::numeric_limits::digits) ) ); *remainder = static_cast ( long_numerator >> static_cast(std::numeric_limits::digits) ); } } WIDE_INTEGER_NODISCARD constexpr auto is_zero() const -> bool { auto it = values.cbegin(); // NOLINT(llvm-qualified-auto,readability-qualified-auto) while((it != values.cend()) && (*it == static_cast(UINT8_C(0)))) // NOLINT(altera-id-dependent-backward-branch) { ++it; } return (it == values.cend()); } template static constexpr auto is_neg(const uintwide_t&, // NOLINT(hicpp-named-parameter,readability-named-parameter) std::enable_if_t<(!RePhraseIsSigned), int>* = nullptr) -> bool // NOLINT(hicpp-named-parameter,readability-named-parameter) { return false; } template static constexpr auto is_neg(const uintwide_t& a, // NOLINT(hicpp-named-parameter,readability-named-parameter) std::enable_if_t* = nullptr) -> bool // NOLINT(hicpp-named-parameter,readability-named-parameter) { return (static_cast(static_cast(a.values.back() >> static_cast(std::numeric_limits::limb_type>::digits - 1)) & 1U) != 0U); } static constexpr auto from_rep(const representation_type& other_rep) -> uintwide_t { uintwide_t result { }; // Create a factory-like object from another (possibly different) // internal data representation. if(number_of_limbs == other_rep.size()) { result = uintwide_t(other_rep); } else { // In the from_rep() function it is actually possible to have // a source representation that differs in size from the destination // representation. This can happen when using non-standard container // representations for the uintwide_t storage (such as std::vector). // In this case, scale to the size of the destination. constexpr auto local_number_of_limbs = static_cast ( Width2 / static_cast(std::numeric_limits::digits) ); representation_type my_rep(local_number_of_limbs, static_cast(UINT8_C(0))); detail::copy_unsafe(other_rep.cbegin(), detail::advance_and_point(other_rep.cbegin(), (detail::min_unsafe)(local_number_of_limbs, static_cast(other_rep.size()))), my_rep.begin()); result = uintwide_t(static_cast(my_rep)); } return result; } static constexpr auto from_rep(representation_type&& other_rep) noexcept -> uintwide_t { uintwide_t result { }; // Create a factory-like object from another (possibly different) // internal data representation (via move semantics). if(number_of_limbs == other_rep.size()) { result = uintwide_t(static_cast(other_rep)); } else { // In the from_rep() function it is actually possible to have // a source representation that differs in size from the destination // representation. This can happen when using non-standard container // representations for the uintwide_t storage (such as std::vector). // In this case, scale to the size of the destination. // LCOV_EXCL_START constexpr auto local_number_of_limbs = static_cast ( Width2 / static_cast(std::numeric_limits::digits) ); representation_type my_rep(local_number_of_limbs, static_cast(UINT8_C(0))); detail::copy_unsafe(other_rep.cbegin(), detail::advance_and_point(other_rep.cbegin(), (detail::min_unsafe)(local_number_of_limbs, static_cast(other_rep.size()))), my_rep.begin()); result = uintwide_t(static_cast(my_rep)); // LCOV_EXCL_STOP } return result; } static constexpr auto my_fill_char() -> char { return '.'; } static constexpr auto is_not_fill_char(char c) -> bool { return (c != my_fill_char()); } // Define the maximum buffer sizes for extracting // octal, decimal and hexadecimal string representations. static constexpr auto wr_string_max_buffer_size_oct() -> size_t { return static_cast ( static_cast(UINT8_C(8)) + static_cast ( (static_cast(my_width2 % static_cast(UINT8_C(3))) != static_cast(UINT8_C(0))) ? static_cast(UINT8_C(1)) : static_cast(UINT8_C(0)) ) + static_cast(my_width2 / static_cast(UINT8_C(3))) ); } static constexpr auto wr_string_max_buffer_size_hex() -> size_t { return static_cast ( static_cast(UINT8_C(8)) + static_cast ( (static_cast(my_width2 % static_cast(UINT8_C(4))) != static_cast(UINT8_C(0))) ? static_cast(UINT8_C(1)) : static_cast(UINT8_C(0)) ) + static_cast(my_width2 / static_cast(UINT8_C(4))) ); } static constexpr auto wr_string_max_buffer_size_dec() -> size_t { return static_cast ( static_cast(UINT8_C(10)) + static_cast ( static_cast(static_cast(my_width2) * static_cast(UINTMAX_C(301))) / static_cast(UINTMAX_C(1000)) ) ); } #if !defined(WIDE_INTEGER_DISABLE_PRIVATE_CLASS_DATA_MEMBERS) private: #endif representation_type values // NOLINT(readability-identifier-naming) { static_cast(number_of_limbs), static_cast(UINT8_C(0)), typename representation_type::allocator_type() }; #if defined(WIDE_INTEGER_DISABLE_PRIVATE_CLASS_DATA_MEMBERS) private: #endif friend auto ::test_uintwide_t_edge::test_various_isolated_edge_cases() -> bool; // Implement non-member comparison operators. friend constexpr auto operator==(const uintwide_t& u, const uintwide_t& v) -> bool { return (u.compare(v) == static_cast( 0)); } friend constexpr auto operator< (const uintwide_t& u, const uintwide_t& v) -> bool { return (u.compare(v) == static_cast(-1)); } friend constexpr auto operator> (const uintwide_t& u, const uintwide_t& v) -> bool { return (u.compare(v) == static_cast( 1)); } friend constexpr auto operator!=(const uintwide_t& u, const uintwide_t& v) -> bool { return (u.compare(v) != static_cast( 0)); } friend constexpr auto operator<=(const uintwide_t& u, const uintwide_t& v) -> bool { return (u.compare(v) <= static_cast( 0)); } friend constexpr auto operator>=(const uintwide_t& u, const uintwide_t& v) -> bool { return (u.compare(v) >= static_cast( 0)); } // Non-member comparison functions of (uintwide_t cmp IntegralType). template friend constexpr auto operator==(const uintwide_t& u, const IntegralType& v) -> std::enable_if_t::value, bool> { return u == uintwide_t(v); } template friend constexpr auto operator!=(const uintwide_t& u, const IntegralType& v) -> std::enable_if_t::value, bool> { return u != uintwide_t(v); } template friend constexpr auto operator> (const uintwide_t& u, const IntegralType& v) -> std::enable_if_t::value, bool> { return u > uintwide_t(v); } template friend constexpr auto operator< (const uintwide_t& u, const IntegralType& v) -> std::enable_if_t::value, bool> { return u < uintwide_t(v); } template friend constexpr auto operator>=(const uintwide_t& u, const IntegralType& v) -> std::enable_if_t::value, bool> { return u >= uintwide_t(v); } template friend constexpr auto operator<=(const uintwide_t& u, const IntegralType& v) -> std::enable_if_t::value, bool> { return u <= uintwide_t(v); } // Non-member comparison functions of (IntegralType cmp uintwide_t). template friend constexpr auto operator==(const IntegralType& u, const uintwide_t& v) -> std::enable_if_t::value, bool> { return uintwide_t(u) == v; } template friend constexpr auto operator!=(const IntegralType& u, const uintwide_t& v) -> std::enable_if_t::value, bool> { return uintwide_t(u) != v; } template friend constexpr auto operator> (const IntegralType& u, const uintwide_t& v) -> std::enable_if_t::value, bool> { return uintwide_t(u) > v; } template friend constexpr auto operator< (const IntegralType& u, const uintwide_t& v) -> std::enable_if_t::value, bool> { return uintwide_t(u) < v; } template friend constexpr auto operator>=(const IntegralType& u, const uintwide_t& v) -> std::enable_if_t::value, bool> { return uintwide_t(u) >= v; } template friend constexpr auto operator<=(const IntegralType& u, const uintwide_t& v) -> std::enable_if_t::value, bool> { return uintwide_t(u) <= v; } #if !defined(WIDE_INTEGER_DISABLE_FLOAT_INTEROP) // Non-member comparison functions of (uintwide_t cmp FloatingPointType). template friend constexpr auto operator==(const uintwide_t& u, const FloatingPointType& f) -> std::enable_if_t::value, bool> { return u == uintwide_t(f); } template friend constexpr auto operator!=(const uintwide_t& u, const FloatingPointType& f) -> std::enable_if_t::value, bool> { return u != uintwide_t(f); } template friend constexpr auto operator> (const uintwide_t& u, const FloatingPointType& f) -> std::enable_if_t::value, bool> { return u > uintwide_t(f); } template friend constexpr auto operator< (const uintwide_t& u, const FloatingPointType& f) -> std::enable_if_t::value, bool> { return u < uintwide_t(f); } template friend constexpr auto operator>=(const uintwide_t& u, const FloatingPointType& f) -> std::enable_if_t::value, bool> { return u >= uintwide_t(f); } template friend constexpr auto operator<=(const uintwide_t& u, const FloatingPointType& f) -> std::enable_if_t::value, bool> { return u <= uintwide_t(f); } // Non-member comparison functions of (FloatingPointType cmp uintwide_t). template friend constexpr auto operator==(const FloatingPointType& f, const uintwide_t& v) -> std::enable_if_t::value, bool> { return uintwide_t(f) == v; } template friend constexpr auto operator!=(const FloatingPointType& f, const uintwide_t& v) -> std::enable_if_t::value, bool> { return uintwide_t(f) != v; } template friend constexpr auto operator> (const FloatingPointType& f, const uintwide_t& v) -> std::enable_if_t::value, bool> { return uintwide_t(f) > v; } template friend constexpr auto operator< (const FloatingPointType& f, const uintwide_t& v) -> std::enable_if_t::value, bool> { return uintwide_t(f) < v; } template friend constexpr auto operator>=(const FloatingPointType& f, const uintwide_t& v) -> std::enable_if_t::value, bool> { return uintwide_t(f) >= v; } template friend constexpr auto operator<=(const FloatingPointType& f, const uintwide_t& v) -> std::enable_if_t::value, bool> { return uintwide_t(f) <= v; } #endif // !defined(WIDE_INTEGER_DISABLE_FLOAT_INTEROP) // Non-member binary add, sub, mul, div, mod of (uintwide_t op uintwide_t). friend constexpr auto operator+ (const uintwide_t& u, const uintwide_t& v) -> uintwide_t { return uintwide_t(u).operator+=(v); } friend constexpr auto operator- (const uintwide_t& u, const uintwide_t& v) -> uintwide_t { return uintwide_t(u).operator-=(v); } friend constexpr auto operator* (const uintwide_t& u, const uintwide_t& v) -> uintwide_t { return uintwide_t(u).operator*=(v); } friend constexpr auto operator/ (const uintwide_t& u, const uintwide_t& v) -> uintwide_t { return uintwide_t(u).operator/=(v); } friend constexpr auto operator% (const uintwide_t& u, const uintwide_t& v) -> uintwide_t { return uintwide_t(u).operator%=(v); } // Non-member binary logic operations of (uintwide_t op uintwide_t). friend constexpr auto operator| (const uintwide_t& u, const uintwide_t& v) -> uintwide_t { return uintwide_t(u).operator|=(v); } friend constexpr auto operator^ (const uintwide_t& u, const uintwide_t& v) -> uintwide_t { return uintwide_t(u).operator^=(v); } friend constexpr auto operator& (const uintwide_t& u, const uintwide_t& v) -> uintwide_t { return uintwide_t(u).operator&=(v); } // Non-member binary add, sub, mul, div, mod of (uintwide_t op IntegralType). template friend constexpr auto operator+(const uintwide_t& u, const IntegralType& v) -> std::enable_if_t::value, uintwide_t> { return uintwide_t(u).operator+=(uintwide_t(v)); } template friend constexpr auto operator-(const uintwide_t& u, const IntegralType& v) -> std::enable_if_t::value, uintwide_t> { return uintwide_t(u).operator-=(uintwide_t(v)); } template friend constexpr auto operator*(const uintwide_t& u, const IntegralType& v) -> std::enable_if_t::value, uintwide_t> { return uintwide_t(u).operator*=(uintwide_t(v)); } template friend constexpr auto operator/(const uintwide_t& u, const IntegralType& v) -> std::enable_if_t::value, uintwide_t> { return uintwide_t(u).operator/=(uintwide_t(v)); } template friend constexpr auto operator%(const uintwide_t& u, const IntegralType& v) -> std::enable_if_t<( std::is_integral::value && std::is_signed::value), uintwide_t> { return uintwide_t(u).operator%=(uintwide_t(v)); } template friend constexpr auto operator%(const uintwide_t& u, const IntegralType& v) -> std::enable_if_t<( std::is_integral::value && std::is_unsigned::value && (std::numeric_limits::digits <= std::numeric_limits::digits)), limb_type> { const auto u_is_neg = uintwide_t::is_neg(u); uintwide_t remainder { }; uintwide_t((!u_is_neg) ? u : -u).eval_divide_by_single_limb(v, static_cast(UINT8_C(0)), &remainder); auto u_rem = static_cast(remainder); return ((!u_is_neg) ? u_rem : static_cast(static_cast(~u_rem) + static_cast(UINT8_C(1)))); } template friend constexpr auto operator%(const uintwide_t& u, const IntegralType& v) -> std::enable_if_t<( std::is_integral::value && std::is_unsigned::value && (std::numeric_limits::digits > std::numeric_limits::digits)), uintwide_t> { return uintwide_t(u).operator%=(uintwide_t(v)); } // Non-member binary add, sub, mul, div, mod of (IntegralType op uintwide_t). template friend constexpr auto operator+(const IntegralType& u, const uintwide_t& v) -> std::enable_if_t::value, uintwide_t> { return uintwide_t(u).operator+=(v); } template friend constexpr auto operator-(const IntegralType& u, const uintwide_t& v) -> std::enable_if_t::value, uintwide_t> { return uintwide_t(u).operator-=(v); } template friend constexpr auto operator*(const IntegralType& u, const uintwide_t& v) -> std::enable_if_t::value, uintwide_t> { return uintwide_t(u).operator*=(v); } template friend constexpr auto operator/(const IntegralType& u, const uintwide_t& v) -> std::enable_if_t::value, uintwide_t> { return uintwide_t(u).operator/=(v); } template friend constexpr auto operator%(const IntegralType& u, const uintwide_t& v) -> std::enable_if_t::value, uintwide_t> { return uintwide_t(u).operator%=(v); } #if !defined(WIDE_INTEGER_DISABLE_FLOAT_INTEROP) // Non-member binary add, sub, mul, div, mod of (uintwide_t op FloatingPointType). template friend constexpr auto operator+(const uintwide_t& u, const FloatingPointType& f) -> std::enable_if_t::value, uintwide_t> { return uintwide_t(u).operator+=(uintwide_t(f)); } template friend constexpr auto operator-(const uintwide_t& u, const FloatingPointType& f) -> std::enable_if_t::value, uintwide_t> { return uintwide_t(u).operator-=(uintwide_t(f)); } template friend constexpr auto operator*(const uintwide_t& u, const FloatingPointType& f) -> std::enable_if_t::value, uintwide_t> { return uintwide_t(u).operator*=(uintwide_t(f)); } template friend constexpr auto operator/(const uintwide_t& u, const FloatingPointType& f) -> std::enable_if_t::value, uintwide_t> { return uintwide_t(u).operator/=(uintwide_t(f)); } template friend constexpr auto operator%(const uintwide_t& u, const FloatingPointType& f) -> std::enable_if_t::value, uintwide_t> { return uintwide_t(u).operator%=(uintwide_t(f)); } // Non-member binary add, sub, mul, div, mod of (FloatingPointType op uintwide_t). template friend constexpr auto operator+(const FloatingPointType& f, const uintwide_t& v) -> std::enable_if_t::value, uintwide_t> { return uintwide_t(f).operator+=(v); } template friend constexpr auto operator-(const FloatingPointType& f, const uintwide_t& v) -> std::enable_if_t::value, uintwide_t> { return uintwide_t(f).operator-=(v); } template friend constexpr auto operator*(const FloatingPointType& f, const uintwide_t& v) -> std::enable_if_t::value, uintwide_t> { return uintwide_t(f).operator*=(v); } template friend constexpr auto operator/(const FloatingPointType& f, const uintwide_t& v) -> std::enable_if_t::value, uintwide_t> { return uintwide_t(f).operator/=(v); } template friend constexpr auto operator%(const FloatingPointType& f, const uintwide_t& v) -> std::enable_if_t::value, uintwide_t> { return uintwide_t(f).operator%=(v); } #endif // Non-member binary logic operations of (uintwide_t op IntegralType). template friend constexpr auto operator|(const uintwide_t& u, const IntegralType& v) -> std::enable_if_t::value, uintwide_t> { return uintwide_t(u).operator|=(uintwide_t(v)); } template friend constexpr auto operator^(const uintwide_t& u, const IntegralType& v) -> std::enable_if_t::value, uintwide_t> { return uintwide_t(u).operator^=(uintwide_t(v)); } template friend constexpr auto operator&(const uintwide_t& u, const IntegralType& v) -> std::enable_if_t::value, uintwide_t> { return uintwide_t(u).operator&=(uintwide_t(v)); } // Non-member binary binary logic operations of (IntegralType op uintwide_t). template friend constexpr auto operator|(const IntegralType& u, const uintwide_t& v) -> std::enable_if_t::value, uintwide_t> { return uintwide_t(u).operator|=(v); } template friend constexpr auto operator^(const IntegralType& u, const uintwide_t& v) -> std::enable_if_t::value, uintwide_t> { return uintwide_t(u).operator^=(v); } template friend constexpr auto operator&(const IntegralType& u, const uintwide_t& v) -> std::enable_if_t::value, uintwide_t> { return uintwide_t(u).operator&=(v); } // Non-member shift functions of (uintwide_t shift IntegralType). template friend constexpr auto operator<<(const uintwide_t& u, const IntegralType n) -> std::enable_if_t::value, uintwide_t> { return uintwide_t(u).operator<<=(n); } template friend constexpr auto operator>>(const uintwide_t& u, const IntegralType n) -> std::enable_if_t::value, uintwide_t> { return uintwide_t(u).operator>>=(n); } template friend constexpr auto divmod(const uintwide_t& a, // NOLINT(readability-redundant-declaration) const uintwide_t& b, std::enable_if_t<((!OtherIsSignedLeft) && (!OtherIsSignedRight)), int>* p_nullparam) -> std::pair, uintwide_t>; template friend constexpr auto divmod(const uintwide_t& a, // NOLINT(readability-redundant-declaration) const uintwide_t& b, std::enable_if_t<((!OtherIsSignedLeft) && (!OtherIsSignedRight)), int>* p_nullparam) -> std::pair, uintwide_t>; template friend constexpr auto divmod(const uintwide_t& a, // NOLINT(readability-redundant-declaration) const uintwide_t& b, std::enable_if_t<(OtherIsSignedLeft || OtherIsSignedRight), int>* p_nullparam) -> std::pair, uintwide_t>; #if (defined(__cpp_lib_to_chars) && (__cpp_lib_to_chars >= 201611L)) template friend constexpr auto from_chars(const char* first, // NOLINT(readability-redundant-declaration) const char* last, uintwide_t& x, int base) -> std::from_chars_result; #endif explicit constexpr uintwide_t(const representation_type& other_rep) : values(static_cast(other_rep)) { } explicit constexpr uintwide_t(representation_type&& other_rep) noexcept : values(static_cast(other_rep)) { } template const* = nullptr> static constexpr auto extract_hex_digits(uintwide_t& tu, char* pstr, const bool is_uppercase) -> unsigned_fast_type { constexpr auto mask = static_cast(UINT8_C(0xF)); auto dst = static_cast(UINT8_C(0)); while(!tu.is_zero()) // NOLINT(altera-id-dependent-backward-branch) { auto c = static_cast(*tu.values.cbegin() & mask); if (c <= static_cast(INT8_C( 9))) { c = static_cast(c + static_cast(INT8_C(0x30))); } else if((c >= static_cast(INT8_C(0xA))) && (c <= static_cast(INT8_C(0xF)))) { c = static_cast(c + (is_uppercase ? static_cast(INT8_C(55)) : static_cast(INT8_C(87)))); } *(--pstr) = c; // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) ++dst; tu >>= static_cast(UINT8_C(4)); } return dst; } template static constexpr auto compare_ranges( InputIteratorLeftType a, InputIteratorRightType b, const unsigned_fast_type count) -> std::int_fast8_t { auto n_return = static_cast(INT8_C(0)); detail::iterator_detail::reverse_iterator pa(detail::advance_and_point(a, count)); detail::iterator_detail::reverse_iterator pb(detail::advance_and_point(b, count)); while(pa != detail::iterator_detail::reverse_iterator(a)) // NOLINT(altera-id-dependent-backward-branch) { using value_left_type = typename detail::iterator_detail::iterator_traits::value_type; const auto value_a = *pa++; const auto value_b = static_cast(*pb++); if(value_a != value_b) { n_return = static_cast ( (value_a > value_b) ? static_cast(INT8_C(1)) : static_cast(INT8_C(-1)) ); break; } } return n_return; } template struct digits_ratio { using local_unknown_builtin_integral_type = UnknownBuiltInIntegralType; using local_unsigned_conversion_type = typename detail::uint_type_helper< std::numeric_limits::is_signed ? static_cast(std::numeric_limits::digits + 1) : static_cast(std::numeric_limits::digits + 0)>::exact_unsigned_type; static constexpr unsigned_fast_type value = static_cast( std::numeric_limits::digits / std::numeric_limits::digits); template static constexpr auto extract(InputIteratorLeft p_limb, unsigned_fast_type limb_count) -> local_unknown_builtin_integral_type { using local_limb_type = typename detail::iterator_detail::iterator_traits::value_type; using left_difference_type = typename detail::iterator_detail::iterator_traits::difference_type; auto u = static_cast(UINT8_C(0)); constexpr auto shift_lim = static_cast ( std::numeric_limits::digits ); for(auto i = static_cast(UINT8_C(0)); ( // NOLINT(altera-id-dependent-backward-branch) (i < limb_count) && (static_cast(static_cast(std::numeric_limits::digits) * i) < shift_lim) ); ++i) { u = static_cast ( u | static_cast(static_cast(*detail::advance_and_point(p_limb, static_cast(i))) << static_cast(static_cast(std::numeric_limits::digits) * i)) ); } return static_cast(u); } }; // Implement a function that extracts any built-in signed or unsigned integral type. template::value>> WIDE_INTEGER_NODISCARD constexpr auto extract_builtin_integral_type() const -> UnknownBuiltInIntegralType { using local_unknown_integral_type = UnknownBuiltInIntegralType; using digits_ratio_type = digits_ratio; const auto ilim = (detail::min_unsafe)(static_cast(digits_ratio_type::value), static_cast(values.size())); // Handle cases for which the input parameter is less wide // or equally as wide as the limb width or wider than the limb width. return ((digits_ratio_type::value < static_cast(UINT8_C(2))) ? static_cast(*values.cbegin()) : digits_ratio_type::extract(values.cbegin(), ilim)); } #if !defined(WIDE_INTEGER_DISABLE_FLOAT_INTEROP) // Implement a function that extracts any built-in floating-point type. template::value>> WIDE_INTEGER_NODISCARD constexpr auto extract_builtin_floating_point_type() const -> FloatingPointType { using local_unsigned_wide_integer_type = uintwide_t; using local_builtin_float_type = FloatingPointType; const auto u_is_neg = is_neg(*this); const local_unsigned_wide_integer_type u((!u_is_neg) ? *this : -*this); const auto my_msb = static_cast(msb(u)); const auto ilim = static_cast ( static_cast( static_cast(my_msb + static_cast(1U)) / static_cast(std::numeric_limits::digits)) + static_cast((static_cast(static_cast(my_msb + static_cast(1U)) % static_cast(std::numeric_limits::digits)) != static_cast(UINT8_C(0))) ? static_cast(1U) : static_cast(UINT8_C(0))) ); auto a = static_cast(0.0F); constexpr auto one_ldbl = static_cast(1.0L); auto ldexp_runner = one_ldbl; auto ui = detail::advance_and_point(u.values.cbegin(), static_cast(UINT8_C(0))); // NOLINT(llvm-qualified-auto,readability-qualified-auto) for(auto i = static_cast(UINT8_C(0)); i < ilim; ++i) // NOLINT(altera-id-dependent-backward-branch) { auto ld = static_cast(0.0L); auto lm_mask = static_cast(UINT8_C(1)); for(auto j = static_cast(UINT8_C(0)); j < static_cast(std::numeric_limits::digits); ++j) { if(static_cast(*ui & lm_mask) != static_cast(UINT8_C(0))) { ld = static_cast(ld + ldexp_runner); } constexpr auto two_ldbl = static_cast(2.0L); lm_mask = static_cast (lm_mask << static_cast(UINT8_C(1))); ldexp_runner = static_cast(ldexp_runner * two_ldbl); } a += static_cast(ld); ++ui; } return static_cast((!u_is_neg) ? a : static_cast(-a)); } #endif template static constexpr auto eval_mul_unary( uintwide_t& u, const uintwide_t& v, std::enable_if_t<((OtherWidth2 / std::numeric_limits::digits) < number_of_limbs_karatsuba_threshold)>* p_nullparam = nullptr) -> void { static_cast(p_nullparam == nullptr); // Unary multiplication function using schoolbook multiplication, // but we only need to retain the low half of the n*n algorithm. // In other words, this is an n*n->n bit multiplication. using local_other_wide_integer_type = uintwide_t; const auto local_other_number_of_limbs = local_other_wide_integer_type::number_of_limbs; using local_other_representation_type = typename local_other_wide_integer_type::representation_type; local_other_representation_type result { static_cast(local_other_number_of_limbs), static_cast(UINT8_C(0)), typename representation_type::allocator_type() }; eval_multiply_n_by_n_to_lo_part(result.begin(), u.values.cbegin(), v.values.cbegin(), local_other_number_of_limbs); detail::copy_unsafe(result.cbegin(), detail::advance_and_point(result.cbegin(), local_other_number_of_limbs), u.values.begin()); } template static constexpr auto eval_mul_unary( uintwide_t& u, const uintwide_t& v, std::enable_if_t<((OtherWidth2 / std::numeric_limits::digits) >= number_of_limbs_karatsuba_threshold)>* p_nullparam = nullptr) -> void { static_cast(p_nullparam == nullptr); // Unary multiplication function using Karatsuba multiplication. constexpr auto local_number_of_limbs = uintwide_t::number_of_limbs; // TBD: Can use specialized allocator or memory pool for these arrays. // Good examples for this (both threaded as well as non-threaded) // can be found in the wide_decimal project. using result_array_type = std::conditional_t::value, detail::fixed_static_array (number_of_limbs * static_cast(UINT8_C(2)))>, detail::fixed_dynamic_array(number_of_limbs * static_cast(UINT8_C(2))), typename std::allocator_traits::value, std::allocator, AllocatorType>>::template rebind_alloc>>; using storage_array_type = std::conditional_t::value, detail::fixed_static_array (number_of_limbs * static_cast(UINT8_C(4)))>, detail::fixed_dynamic_array(number_of_limbs * static_cast(UINT8_C(4))), typename std::allocator_traits::value, std::allocator, AllocatorType>>::template rebind_alloc>>; result_array_type result { }; storage_array_type t { }; eval_multiply_kara_n_by_n_to_2n(result.begin(), u.values.cbegin(), v.values.cbegin(), local_number_of_limbs, t.begin()); detail::copy_unsafe(result.cbegin(), result.cbegin() + local_number_of_limbs, u.values.begin()); } template static constexpr auto eval_add_n( ResultIterator r, InputIteratorLeft u, InputIteratorRight v, const unsigned_fast_type count, const limb_type carry_in = static_cast(UINT8_C(0))) -> limb_type { auto carry_out = static_cast(carry_in); using local_limb_type = typename detail::iterator_detail::iterator_traits::value_type; static_assert ( (std::numeric_limits::digits == std::numeric_limits::value_type>::digits) && (std::numeric_limits::digits == std::numeric_limits::value_type>::digits), "Error: Internals require same widths for left-right-result limb_types at the moment" ); using local_double_limb_type = typename detail::uint_type_helper(std::numeric_limits::digits * 2)>::exact_unsigned_type; using result_difference_type = typename detail::iterator_detail::iterator_traits::difference_type; for(auto i = static_cast(UINT8_C(0)); i < count; ++i) { const auto uv_as_ularge = static_cast ( static_cast(static_cast(*u++) + *v++) + carry_out ); carry_out = static_cast(detail::make_hi(uv_as_ularge)); *detail::advance_and_point(r, static_cast(i)) = static_cast(uv_as_ularge); } return static_cast(carry_out); } template static constexpr auto eval_subtract_n( ResultIterator r, InputIteratorLeft u, InputIteratorRight v, const unsigned_fast_type count, const bool has_borrow_in = false) -> bool { auto has_borrow_out = static_cast ( has_borrow_in ? static_cast(UINT8_C(1)) : static_cast(UINT8_C(0)) ); using local_limb_type = typename detail::iterator_detail::iterator_traits::value_type; static_assert ( (std::numeric_limits::digits == std::numeric_limits::value_type>::digits) && (std::numeric_limits::digits == std::numeric_limits::value_type>::digits), "Error: Internals require same widths for left-right-result limb_types at the moment" ); using local_double_limb_type = typename detail::uint_type_helper(std::numeric_limits::digits * 2)>::exact_unsigned_type; using result_difference_type = typename detail::iterator_detail::iterator_traits::difference_type; for(auto i = static_cast(UINT8_C(0)); i < count; ++i) { const auto uv_as_ularge = static_cast ( static_cast(static_cast(*u++) - *v++) - has_borrow_out ); has_borrow_out = static_cast ( (detail::make_hi(uv_as_ularge) != static_cast(UINT8_C(0))) ? static_cast(UINT8_C(1)) : static_cast(UINT8_C(0)) ); *detail::advance_and_point(r, static_cast(i)) = static_cast(uv_as_ularge); } return (has_borrow_out != static_cast(UINT8_C(0))); } template::number_of_limbs == 4U)> const* = nullptr> static constexpr auto eval_multiply_n_by_n_to_lo_part( ResultIterator r, InputIteratorLeft a, InputIteratorRight b, const unsigned_fast_type count) -> void { static_cast(count); using local_limb_type = typename detail::iterator_detail::iterator_traits::value_type; static_assert ( (std::numeric_limits::digits == std::numeric_limits::value_type>::digits) && (std::numeric_limits::digits == std::numeric_limits::value_type>::digits), "Error: Internals require same widths for left-right-result limb_types at the moment" ); using local_double_limb_type = typename detail::uint_type_helper(static_cast(std::numeric_limits::digits * static_cast(INT8_C(2))))>::exact_unsigned_type; using result_difference_type = typename detail::iterator_detail::iterator_traits::difference_type; using left_difference_type = typename detail::iterator_detail::iterator_traits::difference_type; using left_value_type = typename detail::iterator_detail::iterator_traits::value_type; using right_difference_type = typename detail::iterator_detail::iterator_traits::difference_type; // The algorithm has been derived from the polynomial multiplication. // After the multiplication terms of equal order are grouped // together and retained up to order(3). The carries from the // multiplications are included when adding up the terms. // The results of the intermediate multiplications are stored // in local variables in memory. // Column[CoefficientList[Expand[(a0 + a1 x + a2 x^2 + a3 x^3) (b0 + b1 x + b2 x^2 + b3 x^3)], x]] // a0b0 // a1b0 + a0b1 // a2b0 + a1b1 + a0b2 // a3b0 + a2b1 + a1b2 + a0b3 // See also Wolfram Alpha at: // https://www.wolframalpha.com/input/?i=Column%5BCoefficientList%5B+++Expand%5B%28a0+%2B+a1+x+%2B+a2+x%5E2+%2B+a3+x%5E3%29+%28b0+%2B+b1+x+%2B+b2+x%5E2+%2B+b3+x%5E3%29%5D%2C++++x%5D%5D // ... and take the upper half of the pyramid. // Performance improvement: // (old) kops_per_sec: 33173.50 // (new) kops_per_sec: 95069.43 local_double_limb_type r1 { }; local_double_limb_type r2 { }; const auto a0b0 = static_cast(*detail::advance_and_point(a, static_cast(0)) * static_cast(*detail::advance_and_point(b, static_cast(INT8_C(0))))); const auto a0b1 = static_cast(*detail::advance_and_point(a, static_cast(0)) * static_cast(*detail::advance_and_point(b, static_cast(INT8_C(1))))); const auto a1b0 = static_cast(*detail::advance_and_point(a, static_cast(1)) * static_cast(*detail::advance_and_point(b, static_cast(INT8_C(0))))); const auto a1b1 = static_cast(*detail::advance_and_point(a, static_cast(1)) * static_cast(*detail::advance_and_point(b, static_cast(INT8_C(1))))); // One special case is considered, the case of multiplication // of the form BITS/2 * BITS/2 = BITS. In this case, the algorithm // can be significantly simplified by using only the 'lower-halves' // of the data. if( (*detail::advance_and_point(a, static_cast(INT8_C(2))) == static_cast(UINT8_C(0))) && (*detail::advance_and_point(b, static_cast(INT8_C(2))) == static_cast(UINT8_C(0))) && (*detail::advance_and_point(a, static_cast(INT8_C(3))) == static_cast(UINT8_C(0))) && (*detail::advance_and_point(b, static_cast(INT8_C(3))) == static_cast(UINT8_C(0)))) { r1 = static_cast ( static_cast ( detail::make_hi(a0b0) // LCOV_EXCL_LINE ) + detail::make_lo(a1b0) + detail::make_lo(a0b1) ) ; r2 = static_cast ( static_cast ( detail::make_hi(r1) // LCOV_EXCL_LINE ) + detail::make_lo(a1b1) + detail::make_hi(a0b1) + detail::make_hi(a1b0) ) ; *detail::advance_and_point(r, static_cast(INT8_C(3))) = static_cast ( detail::make_hi(r2) + detail::make_hi(a1b1) ) ; } else { const auto a0b2 = static_cast(*detail::advance_and_point(a, static_cast(INT8_C(0))) * static_cast(*detail::advance_and_point(b, static_cast(INT8_C(2))))); const auto a2b0 = static_cast(*detail::advance_and_point(a, static_cast(INT8_C(2))) * static_cast(*detail::advance_and_point(b, static_cast(INT8_C(0))))); r1 = static_cast ( static_cast ( detail::make_hi(a0b0) ) + detail::make_lo(a1b0) + detail::make_lo(a0b1) ) ; r2 = static_cast ( static_cast ( detail::make_hi(r1) ) + detail::make_lo(a2b0) + detail::make_lo(a1b1) + detail::make_lo(a0b2) + detail::make_hi(a1b0) + detail::make_hi(a0b1) ) ; *detail::advance_and_point(r, static_cast(3)) = static_cast ( detail::make_hi(r2) + static_cast (*detail::advance_and_point(a, static_cast(INT8_C(3))) * static_cast(*detail::advance_and_point(b, static_cast(INT8_C(0))))) + static_cast (*detail::advance_and_point(a, static_cast(INT8_C(2))) * static_cast(*detail::advance_and_point(b, static_cast(INT8_C(1))))) + static_cast (*detail::advance_and_point(a, static_cast(INT8_C(1))) * static_cast(*detail::advance_and_point(b, static_cast(INT8_C(2))))) + static_cast (*detail::advance_and_point(a, static_cast(INT8_C(0))) * static_cast(*detail::advance_and_point(b, static_cast(INT8_C(3))))) + detail::make_hi(a2b0) + detail::make_hi(a1b1) + detail::make_hi(a0b2) ) ; } *detail::advance_and_point(r, static_cast(INT8_C(0))) = static_cast(a0b0); *detail::advance_and_point(r, static_cast(INT8_C(1))) = static_cast(r1); *detail::advance_and_point(r, static_cast(INT8_C(2))) = static_cast(r2); } #if defined(WIDE_INTEGER_HAS_MUL_8_BY_8_UNROLL) template::number_of_limbs == static_cast(UINT32_C(8)))> const* = nullptr> static constexpr auto eval_multiply_n_by_n_to_lo_part( ResultIterator r, InputIteratorLeft a, InputIteratorRight b, const unsigned_fast_type count) -> void { static_cast(count); static_assert ( (std::numeric_limits::value_type>::digits == std::numeric_limits::value_type>::digits) && (std::numeric_limits::value_type>::digits == std::numeric_limits::value_type>::digits), "Error: Internals require same widths for left-right-result limb_types at the moment" ); using local_limb_type = typename detail::iterator_detail::iterator_traits::value_type; using local_double_limb_type = typename detail::uint_type_helper(static_cast(std::numeric_limits::digits * static_cast(INT8_C(2))))>::exact_unsigned_type; using result_difference_type = typename detail::iterator_detail::iterator_traits::difference_type; using left_difference_type = typename detail::iterator_detail::iterator_traits::difference_type; using left_value_type = typename detail::iterator_detail::iterator_traits::value_type; using right_difference_type = typename detail::iterator_detail::iterator_traits::difference_type; // The algorithm has been derived from the polynomial multiplication. // After the multiplication terms of equal order are grouped // together and retained up to order(3). The carries from the // multiplications are included when adding up the terms. // The results of the intermediate multiplications are stored // in local variables in memory. // Column[CoefficientList[Expand[(a0 + a1 x + a2 x^2 + a3 x^3 + a4 x^4 + a5 x^5 + a6 x^6 + a7 x^7) (b0 + b1 x + b2 x^2 + b3 x^3 + b4 x^4 + b5 x^5 + b6 x^6 + b7 x^7)], x]] // a0b0 // a1b0 + a0b1 // a2b0 + a1b1 + a0b2 // a3b0 + a2b1 + a1b2 + a0b3 // a4b0 + a3b1 + a2b2 + a1b3 + a0b4 // a5b0 + a4b1 + a3b2 + a2b3 + a1b4 + a0b5 // a6b0 + a5b1 + a4b2 + a3b3 + a2b4 + a1b5 + a0b6 // a7b0 + a6b1 + a5b2 + a4b3 + a3b4 + a2b5 + a1b6 + a0b7 // See also Wolfram Alpha at: // https://www.wolframalpha.com/input/?i=Column%5BCoefficientList%5B+++Expand%5B%28a0+%2B+a1+x+%2B+a2+x%5E2+%2B+a3+x%5E3%29+%28b0+%2B+b1+x+%2B+b2+x%5E2+%2B+b3+x%5E3%29%5D%2C++++x%5D%5D // ... and take the upper half of the pyramid. const local_double_limb_type a0b0 = *detail::advance_and_point(a, static_cast(INT8_C(0))) * static_cast(*detail::advance_and_point(b, static_cast(INT8_C(0)))); const local_double_limb_type a1b0 = *detail::advance_and_point(a, static_cast(INT8_C(1))) * static_cast(*detail::advance_and_point(b, static_cast(INT8_C(0)))); const local_double_limb_type a0b1 = *detail::advance_and_point(a, static_cast(INT8_C(0))) * static_cast(*detail::advance_and_point(b, static_cast(INT8_C(1)))); const local_double_limb_type a2b0 = *detail::advance_and_point(a, static_cast(INT8_C(2))) * static_cast(*detail::advance_and_point(b, static_cast(INT8_C(0)))); const local_double_limb_type a1b1 = *detail::advance_and_point(a, static_cast(INT8_C(1))) * static_cast(*detail::advance_and_point(b, static_cast(INT8_C(1)))); const local_double_limb_type a0b2 = *detail::advance_and_point(a, static_cast(INT8_C(0))) * static_cast(*detail::advance_and_point(b, static_cast(INT8_C(2)))); const local_double_limb_type a3b0 = *detail::advance_and_point(a, static_cast(INT8_C(3))) * static_cast(*detail::advance_and_point(b, static_cast(INT8_C(0)))); const local_double_limb_type a2b1 = *detail::advance_and_point(a, static_cast(INT8_C(2))) * static_cast(*detail::advance_and_point(b, static_cast(INT8_C(1)))); const local_double_limb_type a1b2 = *detail::advance_and_point(a, static_cast(INT8_C(1))) * static_cast(*detail::advance_and_point(b, static_cast(INT8_C(2)))); const local_double_limb_type a0b3 = *detail::advance_and_point(a, static_cast(INT8_C(0))) * static_cast(*detail::advance_and_point(b, static_cast(INT8_C(3)))); const local_double_limb_type a3b1 = *detail::advance_and_point(a, static_cast(INT8_C(3))) * static_cast(*detail::advance_and_point(b, static_cast(INT8_C(1)))); const local_double_limb_type a2b2 = *detail::advance_and_point(a, static_cast(INT8_C(2))) * static_cast(*detail::advance_and_point(b, static_cast(INT8_C(2)))); const local_double_limb_type a1b3 = *detail::advance_and_point(a, static_cast(INT8_C(1))) * static_cast(*detail::advance_and_point(b, static_cast(INT8_C(3)))); const local_double_limb_type a3b2 = *detail::advance_and_point(a, static_cast(INT8_C(3))) * static_cast(*detail::advance_and_point(b, static_cast(INT8_C(2)))); const local_double_limb_type a2b3 = *detail::advance_and_point(a, static_cast(INT8_C(2))) * static_cast(*detail::advance_and_point(b, static_cast(INT8_C(3)))); const local_double_limb_type a3b3 = *detail::advance_and_point(a, static_cast(INT8_C(3))) * static_cast(*detail::advance_and_point(b, static_cast(INT8_C(3)))); local_double_limb_type rd1 { }; local_double_limb_type rd2 { }; local_double_limb_type rd3 { }; local_double_limb_type rd4 { }; local_double_limb_type rd5 { }; local_double_limb_type rd6 { }; // One special case is considered, the case of multiplication // of the form BITS/2 * BITS/2 = BITS. In this case, the algorithm // can be significantly simplified by using only the 'lower-halves' // of the data. if( (*detail::advance_and_point(a, static_cast(INT8_C(7))) == static_cast(UINT8_C(0))) && (*detail::advance_and_point(b, static_cast(INT8_C(7))) == static_cast(UINT8_C(0))) && (*detail::advance_and_point(a, static_cast(INT8_C(6))) == static_cast(UINT8_C(0))) && (*detail::advance_and_point(b, static_cast(INT8_C(6))) == static_cast(UINT8_C(0))) && (*detail::advance_and_point(a, static_cast(INT8_C(5))) == static_cast(UINT8_C(0))) && (*detail::advance_and_point(b, static_cast(INT8_C(5))) == static_cast(UINT8_C(0))) && (*detail::advance_and_point(a, static_cast(INT8_C(4))) == static_cast(UINT8_C(0))) && (*detail::advance_and_point(b, static_cast(INT8_C(4))) == static_cast(UINT8_C(0)))) { rd1 = static_cast ( detail::make_hi(a0b0) ) + detail::make_lo(a1b0) + detail::make_lo(a0b1) ; rd2 = static_cast ( detail::make_hi(rd1) ) + detail::make_lo(a2b0) + detail::make_lo(a1b1) + detail::make_lo(a0b2) + detail::make_hi(a1b0) + detail::make_hi(a0b1) ; rd3 = static_cast ( detail::make_hi(rd2) ) + detail::make_lo(a3b0) + detail::make_lo(a2b1) + detail::make_lo(a1b2) + detail::make_lo(a0b3) + detail::make_hi(a2b0) + detail::make_hi(a1b1) + detail::make_hi(a0b2) ; rd4 = static_cast ( detail::make_hi(rd3) ) + detail::make_lo(a3b1) + detail::make_lo(a2b2) + detail::make_lo(a1b3) + detail::make_hi(a3b0) + detail::make_hi(a2b1) + detail::make_hi(a1b2) + detail::make_hi(a0b3) ; rd5 = static_cast ( detail::make_hi(rd4) ) + detail::make_lo(a3b2) + detail::make_lo(a2b3) + detail::make_hi(a3b1) + detail::make_hi(a2b2) + detail::make_hi(a1b3) ; rd6 = static_cast ( detail::make_hi(rd5) ) + detail::make_lo(a3b3) + detail::make_hi(a3b2) + detail::make_hi(a2b3) ; *detail::advance_and_point(r, static_cast(INT8_C(7))) = static_cast ( detail::make_hi(rd6) + detail::make_hi(a3b3) ) ; } else { const local_double_limb_type a4b0 = *detail::advance_and_point(a, static_cast(INT8_C(4))) * static_cast(*detail::advance_and_point(b, static_cast(INT8_C(0)))); const local_double_limb_type a0b4 = *detail::advance_and_point(a, static_cast(INT8_C(0))) * static_cast(*detail::advance_and_point(b, static_cast(INT8_C(4)))); const local_double_limb_type a5b0 = *detail::advance_and_point(a, static_cast(INT8_C(5))) * static_cast(*detail::advance_and_point(b, static_cast(INT8_C(0)))); const local_double_limb_type a4b1 = *detail::advance_and_point(a, static_cast(INT8_C(4))) * static_cast(*detail::advance_and_point(b, static_cast(INT8_C(1)))); const local_double_limb_type a1b4 = *detail::advance_and_point(a, static_cast(INT8_C(1))) * static_cast(*detail::advance_and_point(b, static_cast(INT8_C(4)))); const local_double_limb_type a0b5 = *detail::advance_and_point(a, static_cast(INT8_C(0))) * static_cast(*detail::advance_and_point(b, static_cast(INT8_C(5)))); const local_double_limb_type a6b0 = *detail::advance_and_point(a, static_cast(INT8_C(6))) * static_cast(*detail::advance_and_point(b, static_cast(INT8_C(0)))); const local_double_limb_type a5b1 = *detail::advance_and_point(a, static_cast(INT8_C(5))) * static_cast(*detail::advance_and_point(b, static_cast(INT8_C(1)))); const local_double_limb_type a4b2 = *detail::advance_and_point(a, static_cast(INT8_C(4))) * static_cast(*detail::advance_and_point(b, static_cast(INT8_C(2)))); const local_double_limb_type a2b4 = *detail::advance_and_point(a, static_cast(INT8_C(2))) * static_cast(*detail::advance_and_point(b, static_cast(INT8_C(4)))); const local_double_limb_type a1b5 = *detail::advance_and_point(a, static_cast(INT8_C(1))) * static_cast(*detail::advance_and_point(b, static_cast(INT8_C(5)))); const local_double_limb_type a0b6 = *detail::advance_and_point(a, static_cast(INT8_C(0))) * static_cast(*detail::advance_and_point(b, static_cast(INT8_C(6)))); rd1 = static_cast ( detail::make_hi(a0b0) ) + detail::make_lo(a1b0) + detail::make_lo(a0b1) ; rd2 = static_cast ( detail::make_hi(rd1) ) + detail::make_lo(a2b0) + detail::make_lo(a1b1) + detail::make_lo(a0b2) + detail::make_hi(a1b0) + detail::make_hi(a0b1) ; rd3 = static_cast ( detail::make_hi(rd2) ) + detail::make_lo(a3b0) + detail::make_lo(a2b1) + detail::make_lo(a1b2) + detail::make_lo(a0b3) + detail::make_hi(a2b0) + detail::make_hi(a1b1) + detail::make_hi(a0b2) ; rd4 = static_cast ( detail::make_hi(rd3) ) + detail::make_lo(a4b0) + detail::make_lo(a3b1) + detail::make_lo(a2b2) + detail::make_lo(a1b3) + detail::make_lo(a0b4) + detail::make_hi(a3b0) + detail::make_hi(a2b1) + detail::make_hi(a1b2) + detail::make_hi(a0b3) ; rd5 = static_cast ( detail::make_hi(rd4) ) + detail::make_lo(a5b0) + detail::make_lo(a4b1) + detail::make_lo(a3b2) + detail::make_lo(a2b3) + detail::make_lo(a1b4) + detail::make_lo(a0b5) + detail::make_hi(a4b0) + detail::make_hi(a3b1) + detail::make_hi(a2b2) + detail::make_hi(a1b3) + detail::make_hi(a0b4) ; rd6 = static_cast ( detail::make_hi(rd5) ) + detail::make_lo(a6b0) + detail::make_lo(a5b1) + detail::make_lo(a4b2) + detail::make_lo(a3b3) + detail::make_lo(a2b4) + detail::make_lo(a1b5) + detail::make_lo(a0b6) + detail::make_hi(a5b0) + detail::make_hi(a4b1) + detail::make_hi(a3b2) + detail::make_hi(a2b3) + detail::make_hi(a1b4) + detail::make_hi(a0b5) ; *detail::advance_and_point(r, static_cast(INT8_C(7))) = static_cast ( detail::make_hi(rd6) + static_cast (*detail::advance_and_point(a, static_cast(INT8_C(7))) * static_cast(*detail::advance_and_point(b, static_cast(INT8_C(0))))) + static_cast (*detail::advance_and_point(a, static_cast(INT8_C(6))) * static_cast(*detail::advance_and_point(b, static_cast(INT8_C(1))))) + static_cast (*detail::advance_and_point(a, static_cast(INT8_C(5))) * static_cast(*detail::advance_and_point(b, static_cast(INT8_C(2))))) + static_cast (*detail::advance_and_point(a, static_cast(INT8_C(4))) * static_cast(*detail::advance_and_point(b, static_cast(INT8_C(3))))) + static_cast (*detail::advance_and_point(a, static_cast(INT8_C(3))) * static_cast(*detail::advance_and_point(b, static_cast(INT8_C(4))))) + static_cast (*detail::advance_and_point(a, static_cast(INT8_C(2))) * static_cast(*detail::advance_and_point(b, static_cast(INT8_C(5))))) + static_cast (*detail::advance_and_point(a, static_cast(INT8_C(1))) * static_cast(*detail::advance_and_point(b, static_cast(INT8_C(6))))) + static_cast (*detail::advance_and_point(a, static_cast(INT8_C(0))) * static_cast(*detail::advance_and_point(b, static_cast(INT8_C(7))))) + detail::make_hi(a6b0) + detail::make_hi(a5b1) + detail::make_hi(a4b2) + detail::make_hi(a3b3) + detail::make_hi(a2b4) + detail::make_hi(a1b5) + detail::make_hi(a0b6) ) ; } *detail::advance_and_point(r, static_cast(INT8_C(0))) = static_cast(a0b0); *detail::advance_and_point(r, static_cast(INT8_C(1))) = static_cast(rd1); *detail::advance_and_point(r, static_cast(INT8_C(2))) = static_cast(rd2); *detail::advance_and_point(r, static_cast(INT8_C(3))) = static_cast(rd3); *detail::advance_and_point(r, static_cast(INT8_C(4))) = static_cast(rd4); *detail::advance_and_point(r, static_cast(INT8_C(5))) = static_cast(rd5); *detail::advance_and_point(r, static_cast(INT8_C(6))) = static_cast(rd6); } #endif template::number_of_limbs != static_cast(UINT32_C(4))) #if defined(WIDE_INTEGER_HAS_MUL_8_BY_8_UNROLL) && (uintwide_t::number_of_limbs != static_cast(UINT32_C(8))) #endif )> const* = nullptr> static constexpr auto eval_multiply_n_by_n_to_lo_part( ResultIterator r, InputIteratorLeft a, InputIteratorRight b, const unsigned_fast_type count) -> void { static_assert ( (std::numeric_limits::value_type>::digits == std::numeric_limits::value_type>::digits) && (std::numeric_limits::value_type>::digits == std::numeric_limits::value_type>::digits), "Error: Internals require same widths for left-right-result limb_types at the moment" ); using local_limb_type = typename detail::iterator_detail::iterator_traits::value_type; using local_double_limb_type = typename detail::uint_type_helper(std::numeric_limits::digits * 2)>::exact_unsigned_type; detail::fill_unsafe(r, detail::advance_and_point(r, count), static_cast(UINT8_C(0))); #if defined(WIDE_INTEGER_HAS_CLZ_LIMB_OPTIMIZATIONS) auto clz_a = static_cast(UINT8_C(0)); auto clz_b = static_cast(UINT8_C(0)); if(count > static_cast(UINT8_C(0))) { { using input_left_value_type = typename detail::iterator_detail::iterator_traits::value_type; auto it_leading_zeros_a = detail::advance_and_point(a, static_cast(count - static_cast(UINT8_C(1)))); // NOLINT(llvm-qualified-auto,readability-qualified-auto) while( (it_leading_zeros_a != a) // NOLINT(altera-id-dependent-backward-branch) && (*it_leading_zeros_a == static_cast(UINT8_C(0)))) { --it_leading_zeros_a; ++clz_a; } } { using input_right_value_type = typename detail::iterator_detail::iterator_traits::value_type; auto it_leading_zeros_b = detail::advance_and_point(b, static_cast(count - static_cast(UINT8_C(1)))); // NOLINT(llvm-qualified-auto,readability-qualified-auto) while( (it_leading_zeros_b != b) // NOLINT(altera-id-dependent-backward-branch) && (*it_leading_zeros_b == static_cast(UINT8_C(0)))) { --it_leading_zeros_b; ++clz_b; } } } const auto count_b = static_cast(count - clz_b); const auto imax = static_cast(count - clz_a); #else const auto imax = count; #endif for(auto i = static_cast(UINT8_C(0)); i < imax; ++i) // NOLINT(altera-id-dependent-backward-branch) { if(*a != static_cast(UINT8_C(0))) { auto carry = static_cast(UINT8_C(0)); auto r_i_plus_j = detail::advance_and_point(r, i); // NOLINT(llvm-qualified-auto,readability-qualified-auto) auto bj = b; // NOLINT(llvm-qualified-auto,readability-qualified-auto) #if defined(WIDE_INTEGER_HAS_CLZ_LIMB_OPTIMIZATIONS) const auto jmax = (detail::min_unsafe)(static_cast(count - i), static_cast(count_b + static_cast(UINT8_C(1)))); #else const auto jmax = static_cast(count - i); #endif for(auto j = static_cast(UINT8_C(0)); j < jmax; ++j) // NOLINT(altera-id-dependent-backward-branch) { carry = static_cast(carry + static_cast(static_cast(*a) * *bj++)); carry = static_cast(carry + *r_i_plus_j); *r_i_plus_j++ = static_cast(carry); carry = detail::make_hi(carry); } } ++a; } } template static constexpr auto eval_multiply_n_by_n_to_2n( ResultIterator r, InputIteratorLeft a, InputIteratorRight b, const unsigned_fast_type count) -> void { static_assert ( (std::numeric_limits::value_type>::digits == std::numeric_limits::value_type>::digits) && (std::numeric_limits::value_type>::digits == std::numeric_limits::value_type>::digits), "Error: Internals require same widths for left-right-result limb_types at the moment" ); using local_limb_type = typename detail::iterator_detail::iterator_traits::value_type; using local_double_limb_type = typename detail::uint_type_helper(std::numeric_limits::digits * 2)>::exact_unsigned_type; detail::fill_unsafe(r, detail::advance_and_point(r, static_cast(count * 2U)), static_cast(UINT8_C(0))); for(auto i = static_cast(UINT8_C(0)); i < count; ++i) { if(*a != static_cast(UINT8_C(0))) { auto carry = static_cast(UINT8_C(0)); auto r_i_plus_j = detail::advance_and_point(r, i); // NOLINT(llvm-qualified-auto,readability-qualified-auto) auto bj = b; // NOLINT(llvm-qualified-auto,readability-qualified-auto) for(auto j = static_cast(UINT8_C(0)); j < count; ++j) { carry = static_cast ( static_cast ( carry + static_cast(static_cast(*a) * *bj++) ) + *r_i_plus_j ); *r_i_plus_j++ = static_cast(carry); carry = detail::make_hi(carry); } *r_i_plus_j = static_cast(carry); } ++a; } } template static constexpr auto eval_multiply_1d( ResultIterator r, InputIteratorLeft a, const typename detail::iterator_detail::iterator_traits::value_type b, const unsigned_fast_type count) -> limb_type { using local_limb_type = typename detail::iterator_detail::iterator_traits::value_type; using left_value_type = typename detail::iterator_detail::iterator_traits::value_type; static_assert ( (std::numeric_limits::digits == std::numeric_limits::digits), "Error: Internals require same widths for left-right-result limb_types at the moment" ); using local_double_limb_type = typename detail::uint_type_helper(std::numeric_limits::digits * 2)>::exact_unsigned_type; auto carry = static_cast(UINT8_C(0)); if(b == static_cast(UINT8_C(0))) { detail::fill_unsafe(r, detail::advance_and_point(r, count), static_cast(UINT8_C(0))); } else { #if defined(WIDE_INTEGER_HAS_CLZ_LIMB_OPTIMIZATIONS) auto clz_a = static_cast(UINT8_C(0)); if(count > static_cast(UINT8_C(0))) { using input_left_value_type = typename detail::iterator_detail::iterator_traits::value_type; auto it_leading_zeros_a = detail::advance_and_point(a, static_cast(count - static_cast(UINT8_C(1)))); // NOLINT(llvm-qualified-auto,readability-qualified-auto) while( (it_leading_zeros_a != a) // NOLINT(altera-id-dependent-backward-branch) && (*it_leading_zeros_a == static_cast(UINT8_C(0)))) { --it_leading_zeros_a; ++clz_a; } } const auto imax = static_cast(count - clz_a); #else const auto imax = count; #endif auto i = static_cast(UINT8_C(0)); for( ; i < imax; ++i) // NOLINT(altera-id-dependent-backward-branch) { carry = static_cast ( carry + static_cast(static_cast(*a++) * b) ); *r++ = static_cast(carry); carry = static_cast(detail::make_hi(carry)); } #if defined(WIDE_INTEGER_HAS_CLZ_LIMB_OPTIMIZATIONS) for( ; i < count; ++i) { *r++ = static_cast(carry); carry = static_cast(UINT8_C(0)); } #endif } return static_cast(carry); } template static constexpr auto eval_multiply_kara_propagate_carry( InputIteratorLeft t, const unsigned_fast_type n, const typename detail::iterator_detail::iterator_traits::value_type carry) -> void { using local_limb_type = typename detail::iterator_detail::iterator_traits::value_type; using local_double_limb_type = typename detail::uint_type_helper(static_cast(std::numeric_limits::digits * static_cast(INT8_C(2))))>::exact_unsigned_type; auto i = static_cast(UINT8_C(0)); auto carry_out = carry; while((i < n) && (carry_out != static_cast(UINT8_C(0)))) // NOLINT(altera-id-dependent-backward-branch) { const auto uv_as_ularge = static_cast ( static_cast(*t) + carry_out ); carry_out = detail::make_hi(uv_as_ularge); *t++ = static_cast(uv_as_ularge); ++i; } } template static constexpr auto eval_multiply_kara_propagate_borrow( InputIteratorLeft t, const unsigned_fast_type n, const bool has_borrow) -> void { using local_limb_type = typename detail::iterator_detail::iterator_traits::value_type; using local_double_limb_type = typename detail::uint_type_helper(static_cast(std::numeric_limits::digits * static_cast(INT8_C(2))))>::exact_unsigned_type; auto i = static_cast(UINT8_C(0)); auto has_borrow_out = has_borrow; while((i < n) && has_borrow_out) // NOLINT(altera-id-dependent-backward-branch) { auto uv_as_ularge = static_cast(*t); if(has_borrow_out) { --uv_as_ularge; } has_borrow_out = ( detail::make_hi(uv_as_ularge) != static_cast(UINT8_C(0)) ); *t++ = static_cast(uv_as_ularge); ++i; } } template static constexpr auto eval_multiply_kara_n_by_n_to_2n( ResultIterator r, // NOLINT(misc-no-recursion) const InputIteratorLeft a, const InputIteratorRight b, const unsigned_fast_type n, InputIteratorTemp t) -> void { if(n <= static_cast(UINT32_C(48))) { static_cast(t); eval_multiply_n_by_n_to_2n(r, a, b, n); } else { static_assert ( (std::numeric_limits::value_type>::digits == std::numeric_limits::value_type>::digits) && (std::numeric_limits::value_type>::digits == std::numeric_limits::value_type>::digits) && (std::numeric_limits::value_type>::digits == std::numeric_limits::value_type>::digits), "Error: Internals require same widths for left-right-result limb_types at the moment" ); using local_limb_type = typename detail::iterator_detail::iterator_traits::value_type; using result_difference_type = typename detail::iterator_detail::iterator_traits::difference_type; using left_difference_type = typename detail::iterator_detail::iterator_traits::difference_type; using right_difference_type = typename detail::iterator_detail::iterator_traits::difference_type; using temp_difference_type = typename detail::iterator_detail::iterator_traits::difference_type; // Based on "Algorithm 1.3 KaratsubaMultiply", Sect. 1.3.2, page 5 // of R.P. Brent and P. Zimmermann, "Modern Computer Arithmetic", // Cambridge University Press (2011). // The Karatsuba multipliation computes the product of u*v as: // [b^N + b^(N/2)] a1*b1 + [b^(N/2)](a1 - a0)(b0 - b1) + [b^(N/2) + 1] a0*b0 // Here we visualize u and v in two components 0,1 corresponding // to the high and low order parts, respectively. // Step 1 // Calculate a1*b1 and store it in the upper part of r. // Calculate a0*b0 and store it in the lower part of r. // copy r to t0. // Step 2 // Add a1*b1 (which is t2) to the middle two-quarters of r (which is r1) // Add a0*b0 (which is t0) to the middle two-quarters of r (which is r1) // Step 3 // Calculate |a1-a0| in t0 and note the sign (i.e., the borrow flag) // Step 4 // Calculate |b0-b1| in t1 and note the sign (i.e., the borrow flag) // Step 5 // Call kara mul to calculate |a1-a0|*|b0-b1| in (t2), // while using temporary storage in t4 along the way. // Step 6 // Check the borrow signs. If a1-a0 and b0-b1 have the same signs, // then add |a1-a0|*|b0-b1| to r1, otherwise subtract it from r1. const auto nh = static_cast(n / 2U); const InputIteratorLeft a0 = detail::advance_and_point(a, static_cast(0)); const InputIteratorLeft a1 = detail::advance_and_point(a, static_cast(nh)); const InputIteratorRight b0 = detail::advance_and_point(b, static_cast(0)); const InputIteratorRight b1 = detail::advance_and_point(b, static_cast(nh)); ResultIterator r0 = detail::advance_and_point(r, static_cast(0)); ResultIterator r1 = detail::advance_and_point(r, static_cast(nh)); ResultIterator r2 = detail::advance_and_point(r, static_cast(n)); ResultIterator r3 = detail::advance_and_point(r, static_cast(static_cast(n) + static_cast(nh))); InputIteratorTemp t0 = detail::advance_and_point(t, static_cast(0)); InputIteratorTemp t1 = detail::advance_and_point(t, static_cast(nh)); InputIteratorTemp t2 = detail::advance_and_point(t, static_cast(n)); InputIteratorTemp t4 = detail::advance_and_point(t, static_cast(static_cast(n) + static_cast(n))); // Step 1 // a1*b1 -> r2 // a0*b0 -> r0 // r -> t0 eval_multiply_kara_n_by_n_to_2n(r2, a1, b1, nh, t0); eval_multiply_kara_n_by_n_to_2n(r0, a0, b0, nh, t0); detail::copy_unsafe(r0, detail::advance_and_point(r0, static_cast(static_cast(n) * static_cast(2U))), t0); // Step 2 // r1 -> r1 + a1*b1 // r1 -> r1 + a0*b0 auto carry = static_cast(eval_add_n(r1, r1, t2, n)); eval_multiply_kara_propagate_carry(r3, nh, carry); carry = static_cast(eval_add_n(r1, r1, t0, n)); eval_multiply_kara_propagate_carry(r3, nh, carry); // Step 3 // |a1-a0| -> t0 const auto cmp_result_a1a0 = compare_ranges(a1, a0, nh); if(cmp_result_a1a0 == static_cast(INT8_C(1))) { static_cast(eval_subtract_n(t0, a1, a0, nh)); } else if(cmp_result_a1a0 == static_cast(INT8_C(-1))) { static_cast(eval_subtract_n(t0, a0, a1, nh)); } // Step 4 // |b0-b1| -> t1 const auto cmp_result_b0b1 = compare_ranges(b0, b1, nh); if(cmp_result_b0b1 == static_cast(INT8_C(1))) { static_cast(eval_subtract_n(t1, b0, b1, nh)); } else if(cmp_result_b0b1 == static_cast(INT8_C(-1))) { static_cast(eval_subtract_n(t1, b1, b0, nh)); } // Step 5 // |a1-a0|*|b0-b1| -> t2 eval_multiply_kara_n_by_n_to_2n(t2, t0, t1, nh, t4); // Step 6 // either r1 += |a1-a0|*|b0-b1| // or r1 -= |a1-a0|*|b0-b1| if(static_cast(cmp_result_a1a0 * cmp_result_b0b1) == static_cast(INT8_C(1))) { carry = eval_add_n(r1, r1, t2, n); eval_multiply_kara_propagate_carry(r3, nh, carry); } else if(static_cast(cmp_result_a1a0 * cmp_result_b0b1) == static_cast(INT8_C(-1))) { const auto has_borrow = eval_subtract_n(r1, r1, t2, n); eval_multiply_kara_propagate_borrow(r3, nh, has_borrow); } } } constexpr auto eval_divide_knuth(const uintwide_t& other, uintwide_t* remainder = nullptr) -> void { // Use Knuth's long division algorithm. // The loop-ordering of indices in Knuth's original // algorithm has been reversed due to the data format // used here. Several optimizations and combinations // of logic have been carried out in the source code. // See also: // D.E. Knuth, "The Art of Computer Programming, Volume 2: // Seminumerical Algorithms", Addison-Wesley (1998), // Section 4.3.1 Algorithm D and Exercise 16. using local_uint_index_type = unsigned_fast_type; local_uint_index_type u_offset { }; local_uint_index_type v_offset { }; auto crit_u = values.crbegin(); auto crit_v = other.values.crbegin(); while(crit_u != values.crend() && (*crit_u == static_cast(UINT8_C(0)))) // NOLINT(altera-id-dependent-backward-branch) { ++crit_u; ++u_offset; } while(crit_v != other.values.crend() && (*crit_v == static_cast(UINT8_C(0)))) // NOLINT(altera-id-dependent-backward-branch) { ++crit_v; ++v_offset; } if(v_offset == static_cast(number_of_limbs)) { // The denominator is zero. Set the maximum value and return. // This also catches (0 / 0) and sets the maximum value for it. static_cast(operator=(limits_helper_max())); // LCOV_EXCL_LINE if(remainder != nullptr) // LCOV_EXCL_LINE { detail::fill_unsafe(remainder->values.begin(), remainder->values.end(), static_cast(UINT8_C(0))); // LCOV_EXCL_LINE } } else if(u_offset == static_cast(number_of_limbs)) { // The numerator is zero. Do nothing and return. if(remainder != nullptr) { *remainder = uintwide_t(static_cast(UINT8_C(0))); } } else { const auto result_of_compare_left_with_right = compare(other); const auto left_is_less_than_right = (result_of_compare_left_with_right == INT8_C(-1)); const auto left_is_equal_to_right = (result_of_compare_left_with_right == INT8_C( 0)); if(left_is_less_than_right) { // If the denominator is larger than the numerator, // then the result of the division is zero. if(remainder != nullptr) { *remainder = *this; } operator=(static_cast(UINT8_C(0))); } else if(left_is_equal_to_right) { // If the denominator is equal to the numerator, // then the result of the division is one. operator=(static_cast(UINT8_C(1))); if(remainder != nullptr) { *remainder = uintwide_t(static_cast(UINT8_C(0))); } } else { eval_divide_knuth_core(u_offset, v_offset, other, remainder); } } } template constexpr auto eval_divide_knuth_core(const unsigned_fast_type u_offset, // NOLINT(readability-function-cognitive-complexity) const unsigned_fast_type v_offset, const uintwide_t& other, uintwide_t* remainder, std::enable_if_t<(RePhraseWidth2 > static_cast(std::numeric_limits::digits)), int>* p_nullparam = nullptr) -> void { static_cast(p_nullparam); using local_uint_index_type = unsigned_fast_type; if(static_cast(v_offset + static_cast(1U)) == static_cast(number_of_limbs)) { // The denominator has one single limb. // Use a one-dimensional division algorithm. const limb_type short_denominator = *other.values.cbegin(); eval_divide_by_single_limb(short_denominator, u_offset, remainder); } else { // We will now use the Knuth long division algorithm. // Compute the normalization factor d. const auto d = static_cast ( static_cast(static_cast(UINT8_C(1)) << static_cast(std::numeric_limits::digits)) / static_cast(static_cast(*detail::advance_and_point(other.values.cbegin(), static_cast(static_cast(number_of_limbs - 1U) - v_offset))) + static_cast(1U)) ); // Step D1(b), normalize u -> u * d = uu. // Step D1(c): normalize v -> v * d = vv. using uu_array_type = std::conditional_t::value, detail::fixed_static_array , detail::fixed_dynamic_array::value, std::allocator, AllocatorType>>::template rebind_alloc>>; uu_array_type uu { }; representation_type vv { static_cast(number_of_limbs), static_cast(UINT8_C(0)), typename representation_type::allocator_type() // LCOV_EXCL_LINE }; if(d > static_cast(UINT8_C(1))) { { const auto num_limbs_minus_u_ofs = static_cast ( static_cast(number_of_limbs) - u_offset ); const auto u_carry = eval_multiply_1d ( uu.begin(), values.cbegin(), d, static_cast(num_limbs_minus_u_ofs) ); *(uu.begin() + num_limbs_minus_u_ofs) = u_carry; } static_cast ( eval_multiply_1d ( vv.begin(), other.values.cbegin(), d, static_cast(number_of_limbs - v_offset) ) ); } else { detail::copy_unsafe(values.cbegin(), values.cend(), uu.begin()); *(uu.begin() + static_cast(static_cast(number_of_limbs) - u_offset)) = static_cast(UINT8_C(0)); vv = other.values; } // Step D2: Initialize j. // Step D7: Loop on j from m to 0. const auto n = static_cast (number_of_limbs - v_offset); const auto m = static_cast(static_cast(number_of_limbs - u_offset) - n); const auto vj0 = static_cast(static_cast(n - static_cast(UINT8_C(1)))); auto vv_at_vj0_it = detail::advance_and_point(vv.cbegin(), static_cast(vj0)); // NOLINT(llvm-qualified-auto,readability-qualified-auto) const auto vv_at_vj0 = *vv_at_vj0_it--; const auto vv_at_vj0_minus_one = *vv_at_vj0_it; auto values_at_m_minus_j_it = detail::advance_and_point(values.begin(), static_cast(m)); // NOLINT(llvm-qualified-auto,readability-qualified-auto) for(auto j = static_cast(UINT8_C(0)); j <= m; ++j) // NOLINT(altera-id-dependent-backward-branch) { // Step D3 [Calculate q_hat]. // if u[j] == v[j0] // set q_hat = b - 1 // else // set q_hat = (u[j] * b + u[j + 1]) / v[1] const auto uj = static_cast(static_cast(static_cast(static_cast(number_of_limbs + 1U) - 1U) - u_offset) - j); const auto u_j_j1 = static_cast(static_cast(static_cast(*(uu.cbegin() + static_cast(uj))) << static_cast(std::numeric_limits::digits)) + *(uu.cbegin() + static_cast(uj - 1U))); auto q_hat = static_cast ( (*(uu.cbegin() + static_cast(uj)) == vv_at_vj0) ? (std::numeric_limits::max)() : static_cast(u_j_j1 / vv_at_vj0) ); // Decrease q_hat if necessary. // This means that q_hat must be decreased if the // expression [(u[uj] * b + u[uj - 1] - q_hat * v[vj0 - 1]) * b] // exceeds the range of uintwide_t. { const auto u_j_minus_2 = *detail::advance_and_point(uu.cbegin(), static_cast(uj - 2U)); auto t = static_cast ( u_j_j1 - static_cast(q_hat * static_cast(vv_at_vj0)) ); while(true) { const bool t_overflow = (detail::make_hi(t) != static_cast(UINT8_C(0))); const auto lhs = static_cast ( static_cast(vv_at_vj0_minus_one) * q_hat ); const auto rhs = static_cast ( static_cast(t << static_cast(std::numeric_limits::digits)) + u_j_minus_2 ); if(t_overflow || (lhs <= rhs)) { break; } t = static_cast(t + vv_at_vj0); --q_hat; } } { // Step D4: Multiply and subtract. // Replace u[j, ... j + n] by u[j, ... j + n] - q_hat * v[1, ... n]. // Set nv = q_hat * (v[1, ... n]). uu_array_type nv { }; *(nv.begin() + static_cast(n)) = eval_multiply_1d(nv.begin(), vv.cbegin(), q_hat, n); const auto has_borrow = eval_subtract_n ( detail::advance_and_point(uu.begin(), static_cast(static_cast(uj - n))), detail::advance_and_point(uu.cbegin(), static_cast(static_cast(uj - n))), nv.cbegin(), static_cast ( static_cast(n + static_cast(UINT8_C(1))) ) ); // Step D5: Test the remainder. // Set the result value: Set result.m_data[m - j] = q_hat. // Use the condition (u[j] < 0), in other words if the borrow // is non-zero, then step D6 needs to be carried out. if(has_borrow) { --q_hat; // Step D6: Add back. // Add v[1, ... n] back to u[j, ... j + n], // and decrease the result by 1. static_cast ( eval_add_n(uu.begin() + static_cast(static_cast(uj - n)), detail::advance_and_point(uu.cbegin(), static_cast(static_cast(uj - n))), vv.cbegin(), static_cast(n)) ); } } // Get the result data. *values_at_m_minus_j_it = static_cast(q_hat); if(j < m) { --values_at_m_minus_j_it; } } // Clear the data elements that have not // been computed in the division algorithm. { const auto m_plus_one = static_cast ( static_cast(m) + static_cast(UINT8_C(1)) ); detail::fill_unsafe(detail::advance_and_point(values.begin(), m_plus_one), values.end(), static_cast(UINT8_C(0))); } if(remainder != nullptr) { auto rl_it_fwd = // NOLINT(llvm-qualified-auto,readability-qualified-auto) detail::advance_and_point(remainder->values.begin(), static_cast(n)); if(d == static_cast(UINT8_C(1))) { detail::copy_unsafe(uu.cbegin(), detail::advance_and_point(uu.cbegin(), static_cast(static_cast(number_of_limbs - v_offset))), remainder->values.begin()); } else { auto previous_u = static_cast(UINT8_C(0)); auto rl_it_rev = static_cast(rl_it_fwd); auto ul = static_cast ( static_cast ( number_of_limbs - static_cast(v_offset + static_cast(UINT8_C(1))) ) ); for( ; rl_it_rev != remainder->values.rend(); ++rl_it_rev, --ul) // NOLINT(altera-id-dependent-backward-branch) { const auto t = static_cast ( *(uu.cbegin() + static_cast(ul)) + static_cast ( static_cast(previous_u) << static_cast(std::numeric_limits::digits) ) ); *rl_it_rev = static_cast(static_cast(t / d)); previous_u = static_cast(static_cast(t - static_cast(static_cast(d) * *rl_it_rev))); } } detail::fill_unsafe(rl_it_fwd, remainder->values.end(), static_cast(UINT8_C(0))); } } } template constexpr auto eval_divide_knuth_core(const unsigned_fast_type u_offset, const unsigned_fast_type v_offset, const uintwide_t& other, uintwide_t* remainder, std::enable_if_t<(RePhraseWidth2 <= static_cast(std::numeric_limits::digits)), int>* p_nullparam = nullptr) -> void { static_cast(p_nullparam); static_cast(v_offset); // The denominator has one single limb. // Use a one-dimensional division algorithm. const auto short_denominator = static_cast(*other.values.cbegin()); eval_divide_by_single_limb(short_denominator, u_offset, remainder); } template static constexpr auto exceeds_width(IntegralType n) -> bool { return (static_cast(n) >= uintwide_t::my_width2); } WIDE_INTEGER_NODISCARD constexpr auto right_shift_fill_value() const -> limb_type { return static_cast ( (!is_neg(*this)) ? static_cast(UINT8_C(0)) : (std::numeric_limits::max)() ); } template constexpr auto shl(IntegralType n) -> void { const auto offset = (detail::min_unsafe)(static_cast(static_cast(n) / static_cast(std::numeric_limits::digits)), static_cast(number_of_limbs)); const auto left_shift_amount = static_cast(static_cast(n) % static_cast(std::numeric_limits::digits)); if(offset > static_cast(UINT8_C(0))) { detail::copy_backward_unsafe(values.cbegin(), detail::advance_and_point(values.cbegin(), static_cast(number_of_limbs - offset)), detail::advance_and_point(values.begin(), static_cast(number_of_limbs))); detail::fill_unsafe(values.begin(), detail::advance_and_point(values.begin(), static_cast(offset)), static_cast(UINT8_C(0))); } using local_integral_type = unsigned_fast_type; if(left_shift_amount != static_cast(UINT8_C(0))) { auto part_from_previous_value = static_cast(UINT8_C(0)); auto ai = detail::advance_and_point(values.begin(), offset); // NOLINT(llvm-qualified-auto,readability-qualified-auto) while(ai != values.end()) // NOLINT(altera-id-dependent-backward-branch) { const auto t = *ai; *ai++ = static_cast ( static_cast(t << static_cast(left_shift_amount)) | part_from_previous_value ); const auto right_shift_previous_value = static_cast ( static_cast ( static_cast(std::numeric_limits::digits) - static_cast(left_shift_amount) ) ); part_from_previous_value = static_cast(t >> right_shift_previous_value); } } } template constexpr auto shr(IntegralType n) -> void { const auto offset = (detail::min_unsafe)(static_cast(static_cast(n) / static_cast(std::numeric_limits::digits)), static_cast(number_of_limbs)); const auto right_shift_amount = static_cast(static_cast(n) % static_cast(std::numeric_limits::digits)); if(static_cast(offset) > static_cast(UINT8_C(0))) { detail::copy_unsafe(detail::advance_and_point(values.cbegin(), static_cast(offset)), detail::advance_and_point(values.cbegin(), static_cast(number_of_limbs)), values.begin()); detail::fill_unsafe(detail::advance_and_point(values.begin(), static_cast(static_cast(number_of_limbs) - static_cast(offset))), values.end(), right_shift_fill_value()); } using local_integral_type = unsigned_fast_type; if(right_shift_amount != static_cast(UINT8_C(0))) { auto part_from_previous_value = static_cast ( (!is_neg(*this)) ? static_cast(UINT8_C(0)) : static_cast((std::numeric_limits::max)() << static_cast(static_cast(std::numeric_limits::digits) - right_shift_amount)) ); auto r_ai = static_cast ( detail::advance_and_point ( values.begin(), static_cast ( static_cast(number_of_limbs) - offset ) ) ); while(r_ai != values.rend()) // NOLINT(altera-id-dependent-backward-branch) { const auto t = *r_ai; *r_ai++ = static_cast(static_cast(t >> static_cast(right_shift_amount)) | part_from_previous_value); const auto left_shift_previous_value = static_cast ( static_cast ( static_cast(std::numeric_limits::digits) - static_cast(right_shift_amount) ) ); part_from_previous_value = static_cast(t << left_shift_previous_value); } } } // Read string function. constexpr auto rd_string(const char* str_input, const unsigned_fast_type count, const int base_hint) -> bool // NOLINT(readability-function-cognitive-complexity,bugprone-easily-swappable-parameters) { detail::fill_unsafe(values.begin(), values.end(), static_cast(UINT8_C(0))); const auto str_length = static_cast ( (count == (std::numeric_limits::max)()) ? detail::strlen_unsafe(str_input) : count ); auto pos = static_cast(UINT8_C(0)); // Detect: Is there a plus sign? // And if there is a plus sign, skip over the plus sign. if((str_length > static_cast(UINT8_C(0))) && (str_input[static_cast(UINT8_C(0))] == '+')) // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) { ++pos; } auto str_has_neg_sign = false; // Detect: Is there a minus sign? // And if there is a minus sign, skip over the minus sign. if((str_length > static_cast(UINT8_C(0))) && (str_input[static_cast(UINT8_C(0))] == '-')) // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) { str_has_neg_sign = true; ++pos; } // Set the base if the client has supplied a non-zero base-hint. auto base = static_cast(base_hint); if(base == static_cast(UINT8_C(0))) { base = static_cast(UINT8_C(10)); // Perform a dynamic detection of the base. if(str_length > static_cast(static_cast(pos) + static_cast(UINT8_C(0)))) { const auto might_be_oct_or_hex = ((str_input[static_cast(static_cast(pos) + static_cast(UINT8_C(0)))] == '0') && (str_length > static_cast(static_cast(pos) + static_cast(UINT8_C(0))))); // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) if(might_be_oct_or_hex) { if((str_input[static_cast(static_cast(pos) + static_cast(UINT8_C(1)))] >= '0') && (str_input[static_cast(static_cast(pos) + static_cast(UINT8_C(1)))] <= '8')) // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) { // The input format is octal. base = static_cast(UINT8_C(8)); pos = static_cast(static_cast(pos) + static_cast(UINT8_C(1))); } else if((str_input[static_cast(static_cast(pos) + static_cast(UINT8_C(1)))] == 'x') || (str_input[static_cast(static_cast(pos) + static_cast(UINT8_C(1)))] == 'X')) // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) { // The input format is hexadecimal. base = static_cast(UINT8_C(16)); pos = static_cast(static_cast(pos) + static_cast(UINT8_C(2))); } } else if((str_input[static_cast(static_cast(pos) + static_cast(UINT8_C(0)))] >= '0') && (str_input[static_cast(static_cast(pos) + static_cast(UINT8_C(0)))] <= '9')) // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) { // The input format is decimal. ; } } } auto char_is_valid = true; while((pos < str_length) && char_is_valid) // NOLINT(altera-id-dependent-backward-branch) { const auto c = str_input[pos++]; // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) const auto char_is_apostrophe = (c == static_cast(39)); if(!char_is_apostrophe) { if(base == static_cast(UINT8_C(8))) { char_is_valid = ((c >= '0') && (c <= '7')); if(char_is_valid) { const auto uc_oct = static_cast(c - '0'); static_cast(operator<<=(static_cast(UINT8_C(3)))); *values.begin() = static_cast(*values.begin() | uc_oct); } } else if(base == static_cast(UINT8_C(10))) { char_is_valid = ((c >= '0') && (c <= '9')); if(char_is_valid) { const auto uc_dec = static_cast(c - '0'); static_cast(mul_by_limb(static_cast(UINT8_C(10)))); static_cast(operator+=(uc_dec)); } } else if(base == static_cast(UINT8_C(16))) { const auto char_is_a_to_f_lo((c >= 'a') && (c <= 'f')); const auto char_is_a_to_f_hi((c >= 'A') && (c <= 'F')); const auto char_is_0_to_9 ((c >= '0') && (c <= '9')); char_is_valid = (char_is_a_to_f_lo || char_is_a_to_f_hi || char_is_0_to_9); if(char_is_valid) { auto uc_hex = static_cast(UINT8_C(0)); if (char_is_a_to_f_lo) { uc_hex = static_cast(c - static_cast(UINT8_C( 87))); } else if(char_is_a_to_f_hi) { uc_hex = static_cast(c - static_cast(UINT8_C( 55))); } else if(char_is_0_to_9) { uc_hex = static_cast(c - static_cast(UINT8_C(0x30))); } static_cast(operator<<=(static_cast(UINT8_C(4)))); *values.begin() = static_cast(*values.begin() | uc_hex); } } } } if(str_has_neg_sign) { // Exclude this line from code coverage, even though explicit // test cases (search for "result_overshift_is_ok") are known // to cover this line. negate(); // LCOV_EXCL_LINE } return char_is_valid; } constexpr auto bitwise_not() -> void // LCOV_EXCL_LINE { for(auto it = values.begin(); it != values.end(); ++it) // NOLINT(llvm-qualified-auto,readability-qualified-auto,altera-id-dependent-backward-branch) { *it = static_cast(~(*it)); } } // LCOV_EXCL_LINE constexpr auto preincrement() -> void { // Implement self-increment. auto it = values.begin(); // NOLINT(llvm-qualified-auto,readability-qualified-auto) // LCOV_EXCL_LINE do { ++(*it); } while((*it++ == static_cast(UINT8_C(0))) && (it != values.end())); // NOLINT(altera-id-dependent-backward-branch,bugprone-inc-dec-in-conditions) } constexpr auto predecrement() -> void { // Implement self-decrement. auto it = values.begin(); // NOLINT(llvm-qualified-auto,readability-qualified-auto) do { --(*it); } while((*it++ == (std::numeric_limits::max)()) && (it != values.end())); // NOLINT(altera-id-dependent-backward-branch,bugprone-inc-dec-in-conditions) } }; // Define some convenient unsigned wide integer types. using uint64_t = uintwide_t(UINT32_C( 64)), std::uint16_t>; using uint128_t = uintwide_t(UINT32_C( 128)), std::uint32_t>; using uint256_t = uintwide_t(UINT32_C( 256)), std::uint32_t>; using uint512_t = uintwide_t(UINT32_C( 512)), std::uint32_t>; using uint1024_t = uintwide_t(UINT32_C( 1024)), std::uint32_t>; using uint2048_t = uintwide_t(UINT32_C( 2048)), std::uint32_t>; using uint4096_t = uintwide_t(UINT32_C( 4096)), std::uint32_t>; using uint8192_t = uintwide_t(UINT32_C( 8192)), std::uint32_t>; using uint16384_t = uintwide_t(UINT32_C(16384)), std::uint32_t>; using uint32768_t = uintwide_t(UINT32_C(32768)), std::uint32_t>; using uint65536_t = uintwide_t(UINT32_C(65536)), std::uint32_t>; #if !defined(WIDE_INTEGER_DISABLE_TRIVIAL_COPY_AND_STD_LAYOUT_CHECKS) static_assert(std::is_trivially_copyable::value, "uintwide_t must be trivially copyable."); static_assert(std::is_trivially_copyable::value, "uintwide_t must be trivially copyable."); static_assert(std::is_trivially_copyable::value, "uintwide_t must be trivially copyable."); static_assert(std::is_trivially_copyable::value, "uintwide_t must be trivially copyable."); static_assert(std::is_trivially_copyable::value, "uintwide_t must be trivially copyable."); static_assert(std::is_trivially_copyable::value, "uintwide_t must be trivially copyable."); static_assert(std::is_trivially_copyable::value, "uintwide_t must be trivially copyable."); static_assert(std::is_trivially_copyable::value, "uintwide_t must be trivially copyable."); static_assert(std::is_trivially_copyable::value, "uintwide_t must be trivially copyable."); static_assert(std::is_trivially_copyable::value, "uintwide_t must be trivially copyable."); static_assert(std::is_trivially_copyable::value, "uintwide_t must be trivially copyable."); static_assert(std::is_standard_layout::value, "uintwide_t must have standard layout."); static_assert(std::is_standard_layout::value, "uintwide_t must have standard layout."); static_assert(std::is_standard_layout::value, "uintwide_t must have standard layout."); static_assert(std::is_standard_layout::value, "uintwide_t must have standard layout."); static_assert(std::is_standard_layout::value, "uintwide_t must have standard layout."); static_assert(std::is_standard_layout::value, "uintwide_t must have standard layout."); static_assert(std::is_standard_layout::value, "uintwide_t must have standard layout."); static_assert(std::is_standard_layout::value, "uintwide_t must have standard layout."); static_assert(std::is_standard_layout::value, "uintwide_t must have standard layout."); static_assert(std::is_standard_layout::value, "uintwide_t must have standard layout."); static_assert(std::is_standard_layout::value, "uintwide_t must have standard layout."); #endif using int64_t = uintwide_t(UINT32_C( 64)), std::uint16_t, void, true>; using int128_t = uintwide_t(UINT32_C( 128)), std::uint32_t, void, true>; using int256_t = uintwide_t(UINT32_C( 256)), std::uint32_t, void, true>; using int512_t = uintwide_t(UINT32_C( 512)), std::uint32_t, void, true>; using int1024_t = uintwide_t(UINT32_C( 1024)), std::uint32_t, void, true>; using int2048_t = uintwide_t(UINT32_C( 2048)), std::uint32_t, void, true>; using int4096_t = uintwide_t(UINT32_C( 4096)), std::uint32_t, void, true>; using int8192_t = uintwide_t(UINT32_C( 8192)), std::uint32_t, void, true>; using int16384_t = uintwide_t(UINT32_C(16384)), std::uint32_t, void, true>; using int32768_t = uintwide_t(UINT32_C(32768)), std::uint32_t, void, true>; using int65536_t = uintwide_t(UINT32_C(65536)), std::uint32_t, void, true>; #if !defined(WIDE_INTEGER_DISABLE_TRIVIAL_COPY_AND_STD_LAYOUT_CHECKS) static_assert(std::is_trivially_copyable::value, "uintwide_t must be trivially copyable."); static_assert(std::is_trivially_copyable::value, "uintwide_t must be trivially copyable."); static_assert(std::is_trivially_copyable::value, "uintwide_t must be trivially copyable."); static_assert(std::is_trivially_copyable::value, "uintwide_t must be trivially copyable."); static_assert(std::is_trivially_copyable::value, "uintwide_t must be trivially copyable."); static_assert(std::is_trivially_copyable::value, "uintwide_t must be trivially copyable."); static_assert(std::is_trivially_copyable::value, "uintwide_t must be trivially copyable."); static_assert(std::is_trivially_copyable::value, "uintwide_t must be trivially copyable."); static_assert(std::is_trivially_copyable::value, "uintwide_t must be trivially copyable."); static_assert(std::is_trivially_copyable::value, "uintwide_t must be trivially copyable."); static_assert(std::is_trivially_copyable::value, "uintwide_t must be trivially copyable."); static_assert(std::is_standard_layout::value, "uintwide_t must have standard layout."); static_assert(std::is_standard_layout::value, "uintwide_t must have standard layout."); static_assert(std::is_standard_layout::value, "uintwide_t must have standard layout."); static_assert(std::is_standard_layout::value, "uintwide_t must have standard layout."); static_assert(std::is_standard_layout::value, "uintwide_t must have standard layout."); static_assert(std::is_standard_layout::value, "uintwide_t must have standard layout."); static_assert(std::is_standard_layout::value, "uintwide_t must have standard layout."); static_assert(std::is_standard_layout::value, "uintwide_t must have standard layout."); static_assert(std::is_standard_layout::value, "uintwide_t must have standard layout."); static_assert(std::is_standard_layout::value, "uintwide_t must have standard layout."); static_assert(std::is_standard_layout::value, "uintwide_t must have standard layout."); #endif // Insert a base class for numeric_limits<> support. // This class inherits from std::numeric_limits // in order to provide limits for a non-specific unsigned type. template WIDE_INTEGER_NUM_LIMITS_CLASS_TYPE numeric_limits_uintwide_t_base : public std::numeric_limits> { private: using local_wide_integer_type = uintwide_t; public: static constexpr int digits = (!IsSigned) ? static_cast(local_wide_integer_type::my_width2) : static_cast(local_wide_integer_type::my_width2 - static_cast(UINT8_C(1))); static constexpr int digits10 = static_cast((static_cast(digits) * UINTMAX_C(75257499)) / UINTMAX_C(250000000)); static constexpr int max_digits10 = digits10; static constexpr int max_exponent = digits; static constexpr int max_exponent10 = static_cast((static_cast(max_exponent) * UINTMAX_C(75257499)) / UINTMAX_C(250000000)); static constexpr auto (max) () -> local_wide_integer_type { return local_wide_integer_type::template limits_helper_max(); } static constexpr auto (min) () -> local_wide_integer_type { return local_wide_integer_type::template limits_helper_min(); } static constexpr auto lowest() -> local_wide_integer_type { return (min)(); } }; template struct is_integral : public std::is_integral { }; template struct is_integral> : public std::integral_constant { }; #if(__cplusplus >= 201703L) } // namespace math::wide_integer #else } // namespace wide_integer } // namespace math #endif WIDE_INTEGER_NAMESPACE_END namespace std { // Specialization of std::numeric_limits. #if defined(WIDE_INTEGER_NAMESPACE) template WIDE_INTEGER_NUM_LIMITS_CLASS_TYPE numeric_limits> : public WIDE_INTEGER_NAMESPACE::math::wide_integer::numeric_limits_uintwide_t_base { }; #else template WIDE_INTEGER_NUM_LIMITS_CLASS_TYPE numeric_limits<::math::wide_integer::uintwide_t> // NOLINT(cert-dcl58-cpp) : public ::math::wide_integer::numeric_limits_uintwide_t_base { }; #endif } // namespace std WIDE_INTEGER_NAMESPACE_BEGIN #if(__cplusplus >= 201703L) namespace math::wide_integer { #else namespace math { namespace wide_integer { // NOLINT(modernize-concat-nested-namespaces) #endif #if !defined(WIDE_INTEGER_DISABLE_IOSTREAM) // I/O streaming functions. template auto operator<<(std::basic_ostream& out, const uintwide_t& x) -> std::basic_ostream& { std::basic_ostringstream ostr; const std::ios::fmtflags my_flags = out.flags(); const auto show_pos = ((my_flags & std::ios::showpos) == std::ios::showpos); const auto show_base = ((my_flags & std::ios::showbase) == std::ios::showbase); const auto is_uppercase = ((my_flags & std::ios::uppercase) == std::ios::uppercase); std::uint_fast8_t base_rep { }; if ((my_flags & std::ios::oct) == std::ios::oct) { base_rep = static_cast(UINT8_C( 8)); } else if((my_flags & std::ios::hex) == std::ios::hex) { base_rep = static_cast(UINT8_C(16)); } else { base_rep = static_cast(UINT8_C(10)); } const auto field_width = static_cast(out.width()); const auto fill_char_out = static_cast(out.fill()); using local_wide_integer_type = uintwide_t; if(base_rep == static_cast(UINT8_C(8))) { using string_storage_oct_type = std::conditional_t (UINT32_C(2048)), detail::fixed_static_array , detail::fixed_dynamic_array::value, std::allocator, AllocatorType>>::template rebind_alloc>>; // TBD: There is redundant storage of this kind both here // in this subroutine as well as in the wr_string method. string_storage_oct_type str_result { }; // LCOV_EXCL_LINE str_result.fill('\0'); x.wr_string(str_result.begin(), base_rep, show_base, show_pos, is_uppercase, field_width, fill_char_out); static_cast(ostr << str_result.data()); } else if(base_rep == static_cast(UINT8_C(10))) { using string_storage_dec_type = std::conditional_t (UINT32_C(2048)), detail::fixed_static_array , detail::fixed_dynamic_array::value, std::allocator, AllocatorType>>::template rebind_alloc>>; // TBD: There is redundant storage of this kind both here // in this subroutine as well as in the wr_string method. string_storage_dec_type str_result { }; str_result.fill('\0'); x.wr_string(str_result.begin(), base_rep, show_base, show_pos, is_uppercase, field_width, fill_char_out); static_cast(ostr << str_result.data()); } else if(base_rep == static_cast(UINT8_C(16))) { using string_storage_hex_type = std::conditional_t (UINT32_C(2048)), detail::fixed_static_array , detail::fixed_dynamic_array::value, std::allocator, AllocatorType>>::template rebind_alloc>>; // TBD: There is redundant storage of this kind both here // in this subroutine as well as in the wr_string method. string_storage_hex_type str_result { }; str_result.fill('\0'); x.wr_string(str_result.begin(), base_rep, show_base, show_pos, is_uppercase, field_width, fill_char_out); static_cast(ostr << str_result.data()); } return (out << ostr.str()); } template auto operator>>(std::basic_istream& in, uintwide_t& x) -> std::basic_istream& { std::string str_in { }; in >> str_in; using local_wide_integer_type = uintwide_t; x = local_wide_integer_type(str_in.c_str()); return in; } #endif // !defined(WIDE_INTEGER_DISABLE_IOSTREAM) #if(__cplusplus >= 201703L) } // namespace math::wide_integer #else } // namespace wide_integer } // namespace math #endif // Implement various number-theoretical tools. #if(__cplusplus >= 201703L) namespace math::wide_integer { #else namespace math { namespace wide_integer { // NOLINT(modernize-concat-nested-namespaces) #endif namespace detail { #if !defined(WIDE_INTEGER_DISABLE_FLOAT_INTEROP) namespace my_own { template constexpr auto frexp(FloatingPointType x, int* expptr) -> std::enable_if_t<(std::is_floating_point::value && std::numeric_limits::is_iec559 ), FloatingPointType> { using local_floating_point_type = FloatingPointType; const bool x_is_neg { (x < static_cast(0.0L)) }; local_floating_point_type f = (x_is_neg ? -x : x); // NOLINT(altera-id-dependent-backward-branch) int e2 { static_cast(INT8_C(0)) }; constexpr auto two_pow32 = static_cast ( static_cast(0x10000) * static_cast(0x10000) ); while(f >= static_cast(two_pow32)) // NOLINT(altera-id-dependent-backward-branch) { // TBD: Maybe optimize this exponent reduction // with a more clever kind of binary searching. f = static_cast(f / static_cast(two_pow32)); e2 += static_cast(INT32_C(32)); } constexpr auto one_ldbl = static_cast(1.0L); while(f >= static_cast(one_ldbl)) // NOLINT(altera-id-dependent-backward-branch) { constexpr auto two_ldbl = static_cast(2.0L); f = static_cast(f / static_cast(two_ldbl)); ++e2; } if(expptr != nullptr) { *expptr = e2; } return ((!x_is_neg) ? f : -f); } template constexpr auto frexp(FloatingPointType x, int* expptr) -> std::enable_if_t<(std::is_floating_point::value && (!std::numeric_limits::is_iec559)), FloatingPointType> { using std::frexp; return frexp(x, expptr); } template constexpr auto (isfinite)(FloatingPointType x) -> std::enable_if_t<(std::is_floating_point::value && std::numeric_limits::is_iec559 ), bool> { using local_floating_point_type = FloatingPointType; bool x_is_finite { true }; const auto x_is_nan = (x != x); if(x_is_nan) { x_is_finite = false; } else { const auto x_is_inf_pos = (x > (std::numeric_limits::max)()); const auto x_is_inf_neg = (x < std::numeric_limits::lowest()); if(x_is_inf_pos || x_is_inf_neg) { x_is_finite = false; } } return x_is_finite; } template constexpr auto (isfinite)(FloatingPointType x) -> std::enable_if_t<(std::is_floating_point::value && (!std::numeric_limits::is_iec559)), bool> { using std::isfinite; return (isfinite)(x); } } // namespace my_own #endif // !defined(WIDE_INTEGER_DISABLE_FLOAT_INTEROP) template constexpr auto lsb_helper(const UnsignedIntegralType& u) -> unsigned_fast_type { // Compile-time checks. static_assert(( std::is_integral::value && std::is_unsigned::value), "Error: Please check the characteristics of UnsignedIntegralType"); auto result = static_cast(UINT8_C(0)); using local_unsigned_integral_type = UnsignedIntegralType; auto mask = static_cast(u); // NOLINT(altera-id-dependent-backward-branch) // This assumes that at least one bit is set. // Otherwise saturation of the index will occur. // Naive and basic LSB search. // TBD: This could be improved with a binary search // on the lowest bit position of the fundamental type. while(static_cast(static_cast(mask) & static_cast(UINT8_C(1))) == static_cast(UINT8_C(0))) // NOLINT(hicpp-signed-bitwise,altera-id-dependent-backward-branch) { mask = static_cast(mask >> static_cast(UINT8_C(1))); ++result; } return result; } template constexpr auto msb_helper(const UnsignedIntegralType& u) -> unsigned_fast_type { // Compile-time checks. static_assert(( std::is_integral::value && std::is_unsigned::value), "Error: Please check the characteristics of UnsignedIntegralType"); using local_unsigned_integral_type = UnsignedIntegralType; auto i = signed_fast_type { }; // TBD: This could potentially be improved with a binary // search for the highest bit position in the type. for(i = static_cast(std::numeric_limits::digits - 1); i >= static_cast(INT8_C(0)); --i) { const auto bit_is_set = ( static_cast ( u & static_cast(static_cast(1U) << static_cast(i)) ) != static_cast(UINT8_C(0)) ); if(bit_is_set) { break; } } return static_cast((detail::max_unsafe)(static_cast(INT8_C(0)), i)); } template<> constexpr auto msb_helper(const std::uint32_t& u) -> unsigned_fast_type { auto r = static_cast(UINT8_C(0)); auto x = static_cast(u); // Use O(log2[N]) binary-halving in an unrolled loop to find the msb. if(static_cast(x & static_cast(UINT32_C(0xFFFF0000))) != static_cast(UINT8_C(0))) { x = static_cast(x >> static_cast(UINT8_C(16))); r = static_cast(r | static_cast(UINT8_C(16))); } if(static_cast(x & static_cast(UINT32_C(0x0000FF00))) != static_cast(UINT8_C(0))) { x = static_cast(x >> static_cast(UINT8_C( 8))); r = static_cast(r | static_cast(UINT8_C( 8))); } if(static_cast(x & static_cast(UINT32_C(0x000000F0))) != static_cast(UINT8_C(0))) { x = static_cast(x >> static_cast(UINT8_C( 4))); r = static_cast(r | static_cast(UINT8_C( 4))); } if(static_cast(x & static_cast(UINT32_C(0x0000000C))) != static_cast(UINT8_C(0))) { x = static_cast(x >> static_cast(UINT8_C( 2))); r = static_cast(r | static_cast(UINT8_C( 2))); } if(static_cast(x & static_cast(UINT32_C(0x00000002))) != static_cast(UINT8_C(0))) { r = static_cast(r | static_cast(UINT8_C( 1))); } return r; } template<> constexpr auto msb_helper(const std::uint16_t& u) -> unsigned_fast_type { auto r = static_cast(UINT8_C(0)); auto x = static_cast(u); // Use O(log2[N]) binary-halving in an unrolled loop to find the msb. if(static_cast(static_cast(x) & UINT32_C(0xFF00)) != UINT16_C(0)) { x = static_cast(x >> static_cast(UINT8_C(8))); r = static_cast(r | UINT32_C(8)); } if(static_cast(static_cast(x) & UINT32_C(0x00F0)) != UINT16_C(0)) { x = static_cast(x >> static_cast(UINT8_C(4))); r = static_cast(r | UINT32_C(4)); } if(static_cast(static_cast(x) & UINT32_C(0x000C)) != UINT16_C(0)) { x = static_cast(x >> static_cast(UINT8_C(2))); r = static_cast(r | UINT32_C(2)); } if(static_cast(static_cast(x) & UINT32_C(0x0002)) != UINT16_C(0)) { r = static_cast(r | UINT32_C(1)); } return r; } template<> constexpr auto msb_helper(const std::uint8_t& u) -> unsigned_fast_type { auto r = static_cast(UINT8_C(0)); auto x = static_cast(u); // Use O(log2[N]) binary-halving in an unrolled loop to find the msb. if(static_cast(static_cast(x) & UINT32_C(0xF0)) != UINT8_C(0)) { x = static_cast(x >> static_cast(UINT8_C(4))); r = static_cast(r | UINT32_C(4)); } if(static_cast(static_cast(x) & UINT32_C(0x0C)) != UINT8_C(0)) { x = static_cast(x >> static_cast(UINT8_C(2))); r = static_cast(r | UINT32_C(2)); } if(static_cast(static_cast(x) & UINT32_C(0x02)) != UINT8_C(0)) { r = static_cast(r | UINT32_C(1)); } return r; } } // namespace detail template constexpr auto swap(uintwide_t& x, uintwide_t& y) noexcept -> void { if(&x != &y) { detail::swap_unsafe(x, y); } } template constexpr auto lsb(const uintwide_t& x) -> unsigned_fast_type { // Calculate the position of the least-significant bit. // Use a linear search starting from the least significant limb. using local_wide_integer_type = uintwide_t; using local_value_type = typename local_wide_integer_type::representation_type::value_type; auto bpos = static_cast(UINT8_C(0)); auto offset = static_cast(UINT8_C(0)); for(auto it = x.crepresentation().cbegin(); it != x.crepresentation().cend(); ++it, ++offset) // NOLINT(llvm-qualified-auto,readability-qualified-auto,altera-id-dependent-backward-branch) { const auto vi = static_cast(*it & (std::numeric_limits::max)()); if(vi != static_cast(UINT8_C(0))) { bpos = static_cast ( detail::lsb_helper(*it) + static_cast ( static_cast(std::numeric_limits::digits) * offset ) ); break; } } return bpos; } template constexpr auto msb(const uintwide_t& x) -> unsigned_fast_type { // Calculate the position of the most-significant bit. // Use a linear search starting from the most significant limb. using local_wide_integer_type = uintwide_t; using local_value_type = typename local_wide_integer_type::representation_type::value_type; unsigned_fast_type bpos { static_cast(UINT8_C(0)) }; std::uint32_t offset { static_cast(x.crepresentation().size() - 1U) }; for(auto ri { x.crepresentation().crbegin() }; ri != x.crepresentation().crend(); ++ri, --offset) // NOLINT(altera-id-dependent-backward-branch) { const auto vr = static_cast(*ri & (std::numeric_limits::max)()); if(vr != static_cast(UINT8_C(0))) { bpos = static_cast ( detail::msb_helper(*ri) + static_cast ( static_cast(std::numeric_limits::digits) * static_cast(offset) ) ); break; } } return bpos; } template constexpr auto abs(const uintwide_t& x) -> uintwide_t { using local_wide_integer_type = uintwide_t; return ((!local_wide_integer_type::is_neg(x)) ? x : -x); } template constexpr auto sqrt(const uintwide_t& m) -> uintwide_t { // Calculate the square root. using local_wide_integer_type = uintwide_t; local_wide_integer_type s { }; if(m.is_zero() || local_wide_integer_type::is_neg(m)) { s = local_wide_integer_type(static_cast(UINT8_C(0))); } else { // Obtain the initial guess via algorithms // involving the position of the msb. const auto msb_pos = msb(m); const auto msb_pos_mod_2 = static_cast(msb_pos % static_cast(UINT8_C(2))); // Obtain the initial value. const auto left_shift_amount = static_cast ( ((msb_pos_mod_2 == static_cast(UINT8_C(0))) ? static_cast(UINT8_C(1)) + static_cast((msb_pos + static_cast(UINT8_C(0))) / 2U) : static_cast(UINT8_C(1)) + static_cast((msb_pos + static_cast(UINT8_C(1))) / 2U)) ); auto u = static_cast(static_cast(UINT8_C(1))) << left_shift_amount; // Perform the iteration for the square root. // See Algorithm 1.13 SqrtInt, Sect. 1.5.1 // in R.P. Brent and Paul Zimmermann, "Modern Computer Arithmetic", // Cambridge University Press, 2011. for(auto i = static_cast(UINT8_C(0)); i < static_cast(UINT8_C(64)); ++i) { s = u; u = (s + (m / s)) >> static_cast(UINT8_C(1)); if(u >= s) { break; } // LCOV_EXCL_LINE } } return s; } template constexpr auto cbrt(const uintwide_t& m) -> uintwide_t // NOLINT(misc-no-recursion) { // Calculate the cube root. using local_wide_integer_type = uintwide_t; local_wide_integer_type s; if(local_wide_integer_type::is_neg(m)) { s = -cbrt(-m); } else if(m.is_zero()) { s = local_wide_integer_type(static_cast(UINT8_C(0))); } else { // Obtain the initial guess via algorithms // involving the position of the msb. const auto msb_pos = msb(m); // Obtain the initial value. const auto msb_pos_mod_3 = static_cast(msb_pos % static_cast(UINT8_C(3))); const auto left_shift_amount = static_cast ( (msb_pos_mod_3 == unsigned_fast_type { UINT8_C(0) }) ? unsigned_fast_type { UINT8_C(1) } + static_cast(msb_pos / unsigned_fast_type { UINT8_C(3) }) : unsigned_fast_type { UINT8_C(1) } + static_cast((msb_pos + (unsigned_fast_type { UINT8_C(3) } - msb_pos_mod_3)) / unsigned_fast_type { UINT8_C(3) }) ); auto u = static_cast(static_cast(UINT8_C(1))) << left_shift_amount; // Perform the iteration for the k'th root (applied for k = 3). // See Algorithm 1.14 RootInt, Sect. 1.5.2 // in R.P. Brent and Paul Zimmermann, "Modern Computer Arithmetic", // Cambridge University Press, 2011. const auto three_minus_one = static_cast ( static_cast(static_cast(UINT8_C(3)) - static_cast(UINT8_C(1))) ); for(auto i = static_cast(UINT8_C(0)); i < static_cast(UINT8_C(64)); ++i) { s = u; local_wide_integer_type m_over_s_pow_3_minus_one(m); // Use an unrolled loop to divide by s^2 here. // Without a loop, s^2 could potentially overflow. m_over_s_pow_3_minus_one /= s; m_over_s_pow_3_minus_one /= s; u = ((s * three_minus_one) + m_over_s_pow_3_minus_one) / static_cast(UINT8_C(3)); if(u >= s) { break; } } } return s; } template constexpr auto rootk(const uintwide_t& m, std::uint_fast8_t k) -> uintwide_t { // Calculate the k'th root. using local_wide_integer_type = uintwide_t; local_wide_integer_type s; if(k < static_cast(UINT8_C(2))) { s = m; } else if(k == static_cast(UINT8_C(2))) { s = sqrt(m); } else if(k == static_cast(UINT8_C(3))) { s = cbrt(m); } else { if(m.is_zero() || local_wide_integer_type::is_neg(m)) { s = local_wide_integer_type(static_cast(UINT8_C(0))); } else { // Obtain the initial guess via algorithms // involving the position of the msb. const auto msb_pos = msb(m); // Obtain the initial value. const auto msb_pos_mod_k = static_cast(msb_pos % static_cast(k)); const auto left_shift_amount = static_cast ( (msb_pos_mod_k == unsigned_fast_type { UINT8_C(0) }) ? unsigned_fast_type { UINT8_C(1) } + static_cast(msb_pos / unsigned_fast_type { k }) : unsigned_fast_type { UINT8_C(1) } + static_cast((msb_pos + (unsigned_fast_type { k } - msb_pos_mod_k)) / unsigned_fast_type { k }) ); auto u = static_cast(static_cast(UINT8_C(1))) << left_shift_amount; // Perform the iteration for the k'th root. // See Algorithm 1.14 RootInt, Sect. 1.5.2 // in R.P. Brent and Paul Zimmermann, "Modern Computer Arithmetic", // Cambridge University Press, 2011. const auto k_minus_one = static_cast(k - 1U); for(auto i = static_cast(UINT8_C(0)); i < static_cast(UINT8_C(64)); ++i) { s = u; local_wide_integer_type m_over_s_pow_k_minus_one(m); // Use a recursive call here to divide by s^(k - 1). This behaves like // a loop. Without a "loop" (i.e., a recursive call) here, s^(k - 1) // could potentially overflow. detail::div_maker_recursive(m_over_s_pow_k_minus_one, s, static_cast(k_minus_one)); u = ((s * k_minus_one) + m_over_s_pow_k_minus_one) / k; if(u >= s) { break; } } } } return s; } template constexpr auto pow(const uintwide_t& b, const OtherIntegralTypeP& p) -> uintwide_t { // Calculate (b ^ p). using local_wide_integer_type = uintwide_t; using local_limb_type = typename local_wide_integer_type::limb_type; local_wide_integer_type result { }; local_limb_type p0 { static_cast(p) }; if((p0 == static_cast(UINT8_C(0))) && (p == static_cast(0))) { result = local_wide_integer_type(static_cast(UINT8_C(1))); } else if((p0 == static_cast(UINT8_C(1))) && (p == static_cast(UINT8_C(1)))) { result = b; } else if((p0 == static_cast(UINT8_C(2))) && (p == static_cast(UINT8_C(2)))) { result = b; result *= b; } else { result = local_wide_integer_type(static_cast(UINT8_C(1))); local_wide_integer_type y { b }; local_wide_integer_type p_local { p }; while(((p0 = static_cast(p_local)) != static_cast(UINT8_C(0))) || (p_local != static_cast(UINT8_C(0)))) // NOLINT(altera-id-dependent-backward-branch) { if(static_cast(p0 & static_cast(UINT8_C(1))) != static_cast(UINT8_C(0))) { result *= y; } y *= y; p_local >>= 1U; } } return result; } template constexpr auto powm(const uintwide_t& b, const OtherIntegralTypeP& p, const OtherIntegralTypeM& m) -> uintwide_t { // Calculate (b ^ p) % m. using local_normal_width_type = uintwide_t; using local_double_width_type = typename local_normal_width_type::double_width_type; using local_limb_type = typename local_normal_width_type::limb_type; local_normal_width_type result { }; local_double_width_type y { b }; const local_double_width_type m_local { m }; local_limb_type p0 { static_cast(p) }; // NOLINT(altera-id-dependent-backward-branch) if((p0 == static_cast(UINT8_C(0))) && (p == static_cast(static_cast(INT8_C(0))))) { result = local_normal_width_type((m != static_cast(UINT8_C(1))) ? static_cast(UINT8_C(1)) : static_cast(UINT8_C(0))); } else if((p0 == static_cast(UINT8_C(1))) && (p == static_cast(static_cast(INT8_C(1))))) { result = b % m; } else if((p0 == static_cast(UINT8_C(2))) && (p == static_cast(static_cast(INT8_C(2))))) { y *= y; y %= m_local; result = local_normal_width_type(y); } else { using local_other_integral_p_type = OtherIntegralTypeP; local_double_width_type x (static_cast(UINT8_C(1))); local_other_integral_p_type p_local(p); while(((p0 = static_cast(p_local)) != static_cast(UINT8_C(0))) || (p_local != static_cast(0))) // NOLINT(altera-id-dependent-backward-branch) { if(static_cast(p0 & static_cast(UINT8_C(1))) != static_cast(UINT8_C(0))) { x *= y; x %= m_local; } y *= y; y %= m_local; p_local >>= 1U; // NOLINT(hicpp-signed-bitwise) // LCOV_EXCL_LINE } result = local_normal_width_type(x); } return result; } namespace detail { template constexpr auto integer_gcd_reduce(UnsignedShortType u, UnsignedShortType v) -> UnsignedShortType { #if (defined(__cpp_lib_gcd_lcm) && (__cpp_lib_gcd_lcm >= 201606L)) return std::gcd(u, v); #else return detail::gcd_unsafe(u, v); #endif } } // namespace detail template constexpr auto gcd(const uintwide_t& a, // NOLINT(readability-function-cognitive-complexity,bugprone-easily-swappable-parameters) const uintwide_t& b) -> uintwide_t { // This implementation of GCD is an adaptation // of existing code from Boost.Multiprecision. using local_wide_integer_type = uintwide_t; using local_ushort_type = typename local_wide_integer_type::limb_type; using local_ularge_type = typename local_wide_integer_type::double_limb_type; const auto u_is_neg = local_wide_integer_type::is_neg(a); const auto v_is_neg = local_wide_integer_type::is_neg(b); local_wide_integer_type u((!u_is_neg) ? a : -a); local_wide_integer_type v((!v_is_neg) ? b : -b); local_wide_integer_type result; using local_size_type = typename local_wide_integer_type::representation_type::size_type; if(u == v) { // NOLINT(bugprone-branch-clone) // This handles cases having (u = v) and also (u = v = 0). result = std::move(u); // LCOV_EXCL_LINE } else if((static_cast(v) == static_cast(UINT8_C(0))) && (v == static_cast(UINT8_C(0)))) { // This handles cases having (v = 0) with (u != 0). result = std::move(u); // LCOV_EXCL_LINE } else if((static_cast(u) == static_cast(UINT8_C(0))) && (u == static_cast(UINT8_C(0)))) { // This handles cases having (u = 0) with (v != 0). result = std::move(v); // LCOV_EXCL_LINE } else { // Now we handle cases having (u != 0) and (v != 0). // Let shift := lg K, where K is the greatest // power of 2 dividing both u and v. const unsigned_fast_type u_shift = lsb(u); const unsigned_fast_type v_shift = lsb(v); const unsigned_fast_type left_shift_amount = (detail::min_unsafe)(u_shift, v_shift); u >>= u_shift; v >>= v_shift; for(;;) { // Now u and v are both odd, so diff(u, v) is even. // Let u = min(u, v), v = diff(u, v) / 2. if(u == v) { break; } if(u > v) { swap(u, v); } if(v <= (std::numeric_limits::max)()) { const auto my_v_hi = static_cast ( (v.crepresentation().size() >= static_cast(UINT8_C(2))) ? static_cast(*detail::advance_and_point(v.crepresentation().cbegin(), static_cast(UINT8_C(1)))) : static_cast(UINT8_C(0)) ); const auto my_u_hi = static_cast ( (u.crepresentation().size() >= static_cast(UINT8_C(2))) ? static_cast(*detail::advance_and_point(u.crepresentation().cbegin(), static_cast(UINT8_C(1)))) : static_cast(UINT8_C(0)) ); const local_ularge_type v_large = detail::make_large(*v.crepresentation().cbegin(), my_v_hi); const local_ularge_type u_large = detail::make_large(*u.crepresentation().cbegin(), my_u_hi); u = detail::integer_gcd_reduce(v_large, u_large); break; } v -= u; v >>= lsb(v); } result = (u << left_shift_amount); } if(u_is_neg != v_is_neg) { result.negate(); } return result; } template constexpr auto gcd(const UnsignedShortType& u, const UnsignedShortType& v) -> std::enable_if_t<( std::is_integral::value && std::is_unsigned::value), UnsignedShortType> { return detail::gcd_unsafe(u, v); } namespace detail { // Use a local, constexpr, unsafe implementation of the abs-function. template constexpr auto abs_unsafe(const ArithmeticType& val) -> ArithmeticType { if(val > static_cast(INT8_C(0))) { return val; } else // NOLINT(llvm-else-after-return,readability-else-after-return) { ArithmeticType val_unsigned { val }; val_unsigned.negate(); return val_unsigned; } } template constexpr auto lcm_impl(const IntegerType& a, const IntegerType& b) -> IntegerType { using local_integer_type = IntegerType; const local_integer_type ap = detail::abs_unsafe(a); const local_integer_type bp = detail::abs_unsafe(b); const auto a_is_greater_than_b = (ap > bp); const auto gcd_of_ab = gcd(a, b); return (a_is_greater_than_b ? ap * (bp / gcd_of_ab) : bp * (ap / gcd_of_ab)); } } // namespace detail template constexpr auto lcm(const uintwide_t& a, const uintwide_t& b) -> uintwide_t { return detail::lcm_impl(a, b); } template constexpr auto lcm(const UnsignedShortType& a, const UnsignedShortType& b) -> std::enable_if_t<( std::is_integral::value && std::is_unsigned::value), UnsignedShortType> { return detail::lcm_impl(a, b); } template constexpr auto divmod(const uintwide_t& a, const uintwide_t& b, std::enable_if_t<((!IsSignedLeft) && (!IsSignedRight)), int>* p_nullparam) -> std::pair, uintwide_t> { static_cast(p_nullparam); using local_unsigned_wide_type = uintwide_t; local_unsigned_wide_type ua(a); const local_unsigned_wide_type ub(b); local_unsigned_wide_type ur { }; ua.eval_divide_knuth(ub, &ur); using divmod_result_pair_type = std::pair; return divmod_result_pair_type { ua, ur }; } template constexpr auto divmod(const uintwide_t& a, const uintwide_t& b, std::enable_if_t<(IsSignedLeft || IsSignedRight), int>* p_nullparam) -> std::pair, uintwide_t> { static_cast(p_nullparam); using local_unsigned_wide_type = uintwide_t; using local_unknown_signedness_left_type = uintwide_t; using local_unknown_signedness_right_type = uintwide_t; const auto numer_was_neg = local_unknown_signedness_left_type::is_neg(a); const auto denom_was_neg = local_unknown_signedness_right_type::is_neg(b); local_unsigned_wide_type ua((!numer_was_neg) ? a : -a); const local_unsigned_wide_type ub((!denom_was_neg) ? b : -b); local_unsigned_wide_type ur { }; ua.eval_divide_knuth(ub, &ur); using divmod_result_pair_type = std::pair; divmod_result_pair_type result { local_unknown_signedness_left_type { }, local_unknown_signedness_right_type { } }; if(numer_was_neg == denom_was_neg) { result.first = local_unknown_signedness_left_type(ua); result.second = (!numer_was_neg) ? local_unknown_signedness_right_type(ur) : -local_unknown_signedness_right_type(ur); } else { const auto division_is_exact = (ur == static_cast(UINT8_C(0))); if(!division_is_exact) { ++ua; } result.first = local_unknown_signedness_left_type(ua); result.first.negate(); if(!division_is_exact) { ur -= ub; } result.second = local_unknown_signedness_right_type(ur); if(!denom_was_neg) { result.second.negate(); } } return result; } template class uniform_int_distribution { public: using result_type = uintwide_t; struct param_type { public: constexpr param_type() = default; explicit constexpr param_type(const result_type& p_a, const result_type& p_b) // NOLINT(modernize-pass-by-value) : param_a { p_a }, param_b { p_b } { } constexpr param_type(const param_type& other) : param_a(other.param_a), param_b(other.param_b) { } constexpr param_type(param_type&& other) noexcept : param_a(std::move(static_cast(other.param_a))), param_b(std::move(static_cast(other.param_b))) { } ~param_type() = default; constexpr auto operator=(const param_type& other) -> param_type& // NOLINT(cert-oop54-cpp) { if(this != &other) { param_a = other.param_a; param_b = other.param_b; } return *this; } constexpr auto operator=(param_type&& other) noexcept -> param_type& { param_a = std::move(static_cast(other.param_a)); param_b = std::move(static_cast(other.param_b)); return *this; } WIDE_INTEGER_NODISCARD constexpr auto get_a() const -> result_type { return param_a; } WIDE_INTEGER_NODISCARD constexpr auto get_b() const -> result_type { return param_b; } constexpr auto set_a(const result_type& p_a) -> void { param_a = p_a; } constexpr auto set_b(const result_type& p_b) -> void { param_b = p_b; } private: result_type param_a { (std::numeric_limits::min)() }; // NOLINT(readability-identifier-naming) result_type param_b { (std::numeric_limits::max)() }; // NOLINT(readability-identifier-naming) friend constexpr auto operator==(const param_type& lhs, const param_type& rhs) -> bool { return ((lhs.param_a == rhs.param_a) && (lhs.param_b == rhs.param_b)); } friend constexpr auto operator!=(const param_type& lhs, const param_type& rhs) -> bool { return ((lhs.param_a != rhs.param_a) || (lhs.param_b != rhs.param_b)); } }; explicit constexpr uniform_int_distribution ( const result_type& p_a = (std::numeric_limits::min)(), const result_type& p_b = (std::numeric_limits::max)() ) : my_params(p_a, p_b) { } explicit constexpr uniform_int_distribution(const param_type& other_params) // NOLINT(modernize-pass-by-value) : my_params(other_params) { } constexpr uniform_int_distribution(const uniform_int_distribution& other) : my_params(other.my_params) { } constexpr uniform_int_distribution(uniform_int_distribution&& other) noexcept : my_params(std::move(static_cast(other.my_params))) { } ~uniform_int_distribution() = default; auto constexpr operator=(const uniform_int_distribution& other) -> uniform_int_distribution& // NOLINT(cert-oop54-cpp) { if(this != &other) { my_params = other.my_params; } return *this; } auto constexpr operator=(uniform_int_distribution&& other) noexcept -> uniform_int_distribution& { my_params = std::move(static_cast(other.my_params)); return *this; } auto constexpr param(const param_type& new_params) -> void { my_params = new_params; } WIDE_INTEGER_NODISCARD auto param() const -> const param_type& { return my_params; } WIDE_INTEGER_NODISCARD auto a() const -> result_type { return my_params.get_a(); } WIDE_INTEGER_NODISCARD auto b() const -> result_type { return my_params.get_b(); } template::digits> constexpr auto operator()(GeneratorType& generator) -> result_type { return generate ( generator, my_params ); } template::digits> constexpr auto operator()(GeneratorType& input_generator, const param_type& input_params) -> result_type { return generate ( input_generator, input_params ); } private: param_type my_params; // NOLINT(readability-identifier-naming) template::digits> constexpr auto generate(GeneratorType& input_generator, const param_type& input_params) const -> result_type { // Generate random numbers r, where a <= r <= b. auto result = static_cast(static_cast(UINT8_C(0))); using local_limb_type = typename result_type::limb_type; using generator_result_type = typename GeneratorType::result_type; constexpr auto digits_generator_result_type = static_cast(GeneratorResultBits); static_assert(static_cast(digits_generator_result_type % static_cast(UINT8_C(8))) == static_cast(UINT8_C(0)), "Error: Generator result type must have a multiple of 8 bits."); constexpr auto digits_limb_ratio = static_cast(std::numeric_limits::digits / static_cast(INT8_C(8))); constexpr auto digits_gtor_ratio = static_cast(digits_generator_result_type / static_cast(UINT8_C(8))); generator_result_type value = generator_result_type(); auto it = result.representation().begin(); // NOLINT(llvm-qualified-auto,readability-qualified-auto,altera-id-dependent-backward-branch) auto j = static_cast(UINT8_C(0)); while(it != result.representation().end()) // NOLINT(altera-id-dependent-backward-branch) { if(static_cast(j % static_cast(digits_gtor_ratio)) == static_cast(UINT8_C(0))) { value = input_generator(); } const auto right_shift_amount = static_cast ( static_cast(j % digits_gtor_ratio) * static_cast(UINT8_C(8)) ); const auto next_byte = static_cast(value >> right_shift_amount); *it = static_cast ( *it | static_cast(static_cast(next_byte) << static_cast(static_cast(j % digits_limb_ratio) * static_cast(UINT8_C(8)))) ); ++j; if(static_cast(j % digits_limb_ratio) == static_cast(UINT8_C(0))) { ++it; } } if( (input_params.get_a() != (std::numeric_limits::min)()) || (input_params.get_b() != (std::numeric_limits::max)())) { // Note that this restricts the range r to: // r = { [input_generator() % ((b - a) + 1)] + a } result_type range(input_params.get_b() - input_params.get_a()); ++range; result %= range; result += input_params.get_a(); } return result; } friend constexpr auto operator==(const uniform_int_distribution& lhs, const uniform_int_distribution& rhs) -> bool { return (lhs.param() == rhs.param()); } friend constexpr auto operator!=(const uniform_int_distribution& lhs, const uniform_int_distribution& rhs) -> bool { return (lhs.param() != rhs.param()); } }; namespace detail { template auto is_small_prime(const uintwide_t& n) -> bool; template auto is_small_prime(const uintwide_t& np) -> bool { using local_wide_integer_type = uintwide_t; using local_limb_type = typename local_wide_integer_type::limb_type; { const auto n0 = static_cast(np); const auto n_is_even = (static_cast(n0 & static_cast(UINT8_C(1))) == static_cast(UINT8_C(0))); if(n_is_even) { // The prime candidate is not prime because n is even. // Also handle the trivial special case of (n = 2). const auto n_is_two = ((n0 == static_cast(UINT8_C(2))) && (np == static_cast(UINT8_C(2)))); return n_is_two; } if((n0 <= static_cast(UINT8_C(227))) && (np <= static_cast(UINT8_C(227)))) { // This handles the trivial special case of the (non-primality) of 1. const auto n_is_one = ((n0 == static_cast(UINT8_C(1))) && (np == static_cast(UINT8_C(1)))); if(n_is_one) { return false; } // Exclude pure small primes from 3...227. // Table[Prime[i], {i, 2, 49}] = // { // 3, 5, 7, 11, 13, 17, 19, 23, // 29, 31, 37, 41, 43, 47, 53, 59, // 61, 67, 71, 73, 79, 83, 89, 97, // 101, 103, 107, 109, 113, 127, 131, 137, // 139, 149, 151, 157, 163, 167, 173, 179, // 181, 191, 193, 197, 199, 211, 223, 227 // } // See also: // https://www.wolframalpha.com/input/?i=Table%5BPrime%5Bi%5D%2C+%7Bi%2C+2%2C+49%7D%5D constexpr detail::array_detail::array(UINT8_C(48))> small_primes = { static_cast(UINT8_C( 3)), static_cast(UINT8_C( 5)), static_cast(UINT8_C( 7)), static_cast(UINT8_C( 11)), static_cast(UINT8_C( 13)), static_cast(UINT8_C( 17)), static_cast(UINT8_C( 19)), static_cast(UINT8_C( 23)), static_cast(UINT8_C( 29)), static_cast(UINT8_C( 31)), static_cast(UINT8_C( 37)), static_cast(UINT8_C( 41)), static_cast(UINT8_C( 43)), static_cast(UINT8_C( 47)), static_cast(UINT8_C( 53)), static_cast(UINT8_C( 59)), static_cast(UINT8_C( 61)), static_cast(UINT8_C( 67)), static_cast(UINT8_C( 71)), static_cast(UINT8_C( 73)), static_cast(UINT8_C( 79)), static_cast(UINT8_C( 83)), static_cast(UINT8_C( 89)), static_cast(UINT8_C( 97)), static_cast(UINT8_C(101)), static_cast(UINT8_C(103)), static_cast(UINT8_C(107)), static_cast(UINT8_C(109)), static_cast(UINT8_C(113)), static_cast(UINT8_C(127)), static_cast(UINT8_C(131)), static_cast(UINT8_C(137)), static_cast(UINT8_C(139)), static_cast(UINT8_C(149)), static_cast(UINT8_C(151)), static_cast(UINT8_C(157)), static_cast(UINT8_C(163)), static_cast(UINT8_C(167)), static_cast(UINT8_C(173)), static_cast(UINT8_C(179)), static_cast(UINT8_C(181)), static_cast(UINT8_C(191)), static_cast(UINT8_C(193)), static_cast(UINT8_C(197)), static_cast(UINT8_C(199)), static_cast(UINT8_C(211)), static_cast(UINT8_C(223)), static_cast(UINT8_C(227)) }; return detail::binary_search_unsafe(small_primes.cbegin(), small_primes.cend(), n0); } } // Check small factors. // Exclude small prime factors from { 3 ... 53 }. // Product[Prime[i], {i, 2, 16}] = 16294579238595022365 // See also: https://www.wolframalpha.com/input/?i=Product%5BPrime%5Bi%5D%2C+%7Bi%2C+2%2C+16%7D%5D { constexpr std::uint64_t pp0 = UINT64_C(16294579238595022365); const auto m0 = static_cast(np % pp0); if((m0 == static_cast(UINT8_C(0))) || (detail::integer_gcd_reduce(m0, pp0) != static_cast(UINT8_C(1)))) { return false; } } // Exclude small prime factors from { 59 ... 101 }. // Product[Prime[i], {i, 17, 26}] = 7145393598349078859 // See also: https://www.wolframalpha.com/input/?i=Product%5BPrime%5Bi%5D%2C+%7Bi%2C+17%2C+26%7D%5D { constexpr std::uint64_t pp1 = UINT64_C(7145393598349078859); const auto m1 = static_cast(np % pp1); if((m1 == static_cast(UINT8_C(0))) || (detail::integer_gcd_reduce(m1, pp1) != static_cast(UINT8_C(1)))) { return false; } } // Exclude small prime factors from { 103 ... 149 }. // Product[Prime[i], {i, 27, 35}] = 6408001374760705163 // See also: https://www.wolframalpha.com/input/?i=Product%5BPrime%5Bi%5D%2C+%7Bi%2C+27%2C+35%7D%5D { constexpr std::uint64_t pp2 = UINT64_C(6408001374760705163); const auto m2 = static_cast(np % pp2); if((m2 == static_cast(UINT8_C(0))) || (detail::integer_gcd_reduce(m2, pp2) != static_cast(UINT8_C(1)))) { return false; } } // Exclude small prime factors from { 151 ... 191 }. // Product[Prime[i], {i, 36, 43}] = 690862709424854779 // See also: https://www.wolframalpha.com/input/?i=Product%5BPrime%5Bi%5D%2C+%7Bi%2C+36%2C+43%7D%5D { constexpr std::uint64_t pp3 = UINT64_C(690862709424854779); const auto m3 = static_cast(np % pp3); if((m3 == static_cast(UINT8_C(0))) || (detail::integer_gcd_reduce(m3, pp3) != static_cast(UINT8_C(1)))) { return false; } } // Exclude small prime factors from { 193 ... 227 }. // Product[Prime[i], {i, 44, 49}] = 80814592450549 // See also: https://www.wolframalpha.com/input/?i=Product%5BPrime%5Bi%5D%2C+%7Bi%2C+44%2C+49%7D%5D { constexpr std::uint64_t pp4 = UINT64_C(80814592450549); const auto m4 = static_cast(np % pp4); if((m4 == static_cast(UINT8_C(0))) || (detail::integer_gcd_reduce(m4, pp4) != static_cast(UINT8_C(1)))) { return false; } } return false; } } // namespace detail template auto miller_rabin(const uintwide_t& n, // NOLINT(readability-function-cognitive-complexity) const unsigned_fast_type number_of_trials, DistributionType& distribution, GeneratorType& generator) -> bool { // This Miller-Rabin primality test is loosely based on // an adaptation of some code from Boost.Multiprecision. // The Boost.Multiprecision code can be found here: // https://www.boost.org/doc/libs/1_90_0/libs/multiprecision/doc/html/boost_multiprecision/tut/primetest.html // Note: Some comments in this subroutine use the Wolfram Language(TM). // These can be exercised at the web links to WolframAlpha(R) provided. using local_wide_integer_type = uintwide_t; using local_limb_type = typename local_wide_integer_type::limb_type; const local_wide_integer_type np((!local_wide_integer_type::is_neg(n)) ? n : -n); if(detail::is_small_prime(np)) { return true; } const local_wide_integer_type nm1 { np - static_cast(UINT8_C(1)) }; auto local_functor_isone { [](const local_wide_integer_type& t1) { return ( (static_cast(t1) == local_limb_type { UINT8_C(1) }) && (t1 == unsigned { UINT8_C(1) }) ); } }; // Since we have already excluded all small factors // up to and including 227, n is greater than 227. { // Perform a single Fermat test which will // exclude many non-prime candidates. const local_wide_integer_type fn { powm(local_wide_integer_type(static_cast(228U)), nm1, np) }; if(!local_functor_isone(fn)) { return false; } } const unsigned k { static_cast(lsb(nm1)) }; const local_wide_integer_type q { nm1 >> k }; using local_param_type = typename DistributionType::param_type; const local_param_type params { local_wide_integer_type { unsigned { UINT8_C(2) } }, np - unsigned { UINT8_C(2) } }; // Assume the test will pass, even though it usually does not pass. bool result_candidate_is_prime { true }; using local_double_width_type = typename local_wide_integer_type::double_width_type; const local_double_width_type np_dbl { np }; // We will now run the trials. for(std::size_t trial { std::size_t { UINT8_C(0) } }; ((trial < number_of_trials) && result_candidate_is_prime); ++trial) { local_wide_integer_type y { powm(distribution(generator, params), q, np) }; for(auto j = std::size_t { UINT8_C(0) }; ((j < static_cast(k)) && result_candidate_is_prime); // NOLINT(altera-id-dependent-backward-branch) ++j) { if (y == nm1) { // This trial passes and the candidate is very probably prime // within the limits of Miller-Rabin. break; } if(local_functor_isone(y)) { // Failure and the candidate is not prime, but only if this is // not the first step. if(j != std::size_t { UINT8_C(0) }) { result_candidate_is_prime = false; } break; } // Compute y = y^2 mod np. { const local_double_width_type y_dbl { static_cast(y) }; y = static_cast((y_dbl * y_dbl) % np_dbl); } // If we reach the final iteration without hitting nm1, // then the candidate is not prime. if(static_cast(j + std::size_t { UINT8_C(1) }) == k) { result_candidate_is_prime = false; } } } return result_candidate_is_prime; } #if (defined(__cpp_lib_to_chars) && (__cpp_lib_to_chars >= 201611L)) template constexpr auto to_chars(char* first, char* last, const uintwide_t& x, int base) -> std::to_chars_result { using local_wide_integer_type = uintwide_t; const auto base_rep = static_cast(base); const auto show_base = false; const auto show_pos = false; const auto is_uppercase = false; std::to_chars_result result { last, std::errc::value_too_large }; if(base_rep == static_cast(UINT8_C(8))) { using string_storage_oct_type = std::conditional_t (UINT32_C(2048)), detail::fixed_static_array , detail::fixed_dynamic_array::value, std::allocator, AllocatorType>>::template rebind_alloc>>; using local_size_type = typename string_storage_oct_type::size_type; string_storage_oct_type str_temp { }; str_temp.fill(local_wide_integer_type::my_fill_char()); const auto wr_string_is_ok = x.wr_string(str_temp.begin(), base_rep, show_base, show_pos, is_uppercase); auto rit_trim = detail::find_if_unsafe(str_temp.crbegin(), str_temp.crend(), local_wide_integer_type::is_not_fill_char); const auto wr_string_and_trim_is_ok = ( (rit_trim != str_temp.crend()) && wr_string_is_ok ); if(wr_string_and_trim_is_ok) { const auto chars_retrieved = static_cast ( str_temp.size() - static_cast(detail::distance_unsafe(str_temp.crbegin(), rit_trim)) ); const auto chars_to_get = static_cast(detail::distance_unsafe(first, last)); result.ptr = detail::copy_unsafe(str_temp.cbegin(), str_temp.cbegin() + (detail::min_unsafe)(chars_retrieved, chars_to_get), first); result.ec = std::errc(); } } else if(base_rep == static_cast(UINT8_C(16))) { using string_storage_hex_type = std::conditional_t (UINT32_C(2048)), detail::fixed_static_array , detail::fixed_dynamic_array::value, std::allocator, AllocatorType>>::template rebind_alloc>>; using local_size_type = typename string_storage_hex_type::size_type; string_storage_hex_type str_temp { }; str_temp.fill(local_wide_integer_type::my_fill_char()); const auto wr_string_is_ok = x.wr_string(str_temp.begin(), base_rep, show_base, show_pos, is_uppercase); auto rit_trim = detail::find_if_unsafe(str_temp.crbegin(), str_temp.crend(), local_wide_integer_type::is_not_fill_char); const auto wr_string_and_trim_is_ok = ( (rit_trim != str_temp.crend()) && wr_string_is_ok ); if(wr_string_and_trim_is_ok) { const auto chars_retrieved = static_cast ( str_temp.size() - static_cast(detail::distance_unsafe(str_temp.crbegin(), rit_trim)) ); const auto chars_to_get = static_cast(detail::distance_unsafe(first, last)); result.ptr = detail::copy_unsafe(str_temp.cbegin(), str_temp.cbegin() + (detail::min_unsafe)(chars_retrieved, chars_to_get), first); result.ec = std::errc(); } } else { using string_storage_dec_type = std::conditional_t (UINT32_C(2048)), detail::fixed_static_array , detail::fixed_dynamic_array::value, std::allocator, AllocatorType>>::template rebind_alloc>>; using local_size_type = typename string_storage_dec_type::size_type; string_storage_dec_type str_temp { }; str_temp.fill(local_wide_integer_type::my_fill_char()); const auto wr_string_is_ok = x.wr_string(str_temp.begin(), base_rep, show_base, show_pos, is_uppercase); auto rit_trim = detail::find_if_unsafe(str_temp.crbegin(), str_temp.crend(), local_wide_integer_type::is_not_fill_char); const auto wr_string_and_trim_is_ok = ( (rit_trim != str_temp.crend()) && wr_string_is_ok ); if(wr_string_and_trim_is_ok) { const auto chars_retrieved = static_cast ( str_temp.size() - static_cast(detail::distance_unsafe(str_temp.crbegin(), rit_trim)) ); const auto chars_to_get = static_cast(detail::distance_unsafe(first, last)); result.ptr = detail::copy_unsafe(str_temp.cbegin(), str_temp.cbegin() + (detail::min_unsafe)(chars_retrieved, chars_to_get), first); result.ec = std::errc(); } } return result; } template constexpr auto from_chars(const char* first, const char* last, uintwide_t& x, int base) -> std::from_chars_result { using local_wide_integer_type = uintwide_t; using local_wide_integer_type = uintwide_t; using local_limb_type = typename local_wide_integer_type::limb_type; detail::fill_unsafe(x.values.begin(), x.values.end(), static_cast(UINT8_C(0))); const auto str_len = static_cast(detail::distance_unsafe(first, last)); const auto result_rd_string_is_ok = x.rd_string(first, str_len, base); std::from_chars_result result { }; if(result_rd_string_is_ok) { result = std::from_chars_result { last, std::errc() }; } else { result = std::from_chars_result { last, std::errc::result_out_of_range }; detail::fill_unsafe(x.values.begin(), x.values.end(), static_cast(UINT8_C(0))); } return result; } #endif #if !defined(WIDE_INTEGER_DISABLE_TO_STRING) template auto to_string(const uintwide_t& x) -> std::string { using local_wide_integer_type = uintwide_t; using string_storage_dec_type = std::conditional_t (UINT32_C(2048)), detail::fixed_static_array , detail::fixed_dynamic_array::value, std::allocator, AllocatorType>>::template rebind_alloc>>; using local_size_type = typename string_storage_dec_type::size_type; string_storage_dec_type str_temp { }; // LCOV_EXCL_LINE str_temp.fill(local_wide_integer_type::my_fill_char()); const auto base_rep = static_cast(UINT8_C(10)); const auto show_base = false; const auto show_pos = false; const auto is_uppercase = false; const auto wr_string_is_ok = x.wr_string(str_temp.begin(), base_rep, show_base, show_pos, is_uppercase); auto rit_trim = detail::find_if_unsafe(str_temp.crbegin(), str_temp.crend(), local_wide_integer_type::is_not_fill_char); const auto wr_string_and_trim_is_ok = ( (rit_trim != str_temp.crend()) && wr_string_is_ok ); std::string str_result { }; if(wr_string_and_trim_is_ok) { const auto str_result_size = static_cast ( str_temp.size() - static_cast(detail::distance_unsafe(str_temp.crbegin(), rit_trim)) ); detail::fill_unsafe(str_temp.begin() + str_result_size, str_temp.end(), '\0'); str_result = std::string(str_temp.data()); } return str_result; } #endif template::value_type>::digits == std::numeric_limits::digits> const*> constexpr auto import_bits(uintwide_t& val, ForwardIterator first, ForwardIterator last, unsigned chunk_size, bool msv_first) -> uintwide_t& { // This subroutine implements limb-by-limb import of bit-chunks. // This template specialization is intended for full chunk sizes, // whereby the width of the chunk's value type equals the limb's width. // If, however, the chunk_size to import is not "full", then this // subroutine uses slow bit-by-bit methods. // The order of bit-chunks imported is set by msv_first. using local_unsigned_wide_integer_type = uintwide_t; using local_result_iterator_type = typename local_unsigned_wide_integer_type::reverse_iterator; using local_result_value_type = typename local_result_iterator_type::value_type; using local_input_iterator_type = ForwardIterator; using local_input_value_type = typename detail::iterator_detail::iterator_traits::value_type; static_assert(std::numeric_limits::digits == std::numeric_limits::digits, "Error: Mismatch for input element width and result uintwide_t limb width"); if(chunk_size == static_cast(UINT8_C(0))) { chunk_size = static_cast(std::numeric_limits::digits); } chunk_size = (detail::min_unsafe)(static_cast(std::numeric_limits::digits), chunk_size); const auto chunk_is_whole = (chunk_size == static_cast(std::numeric_limits::digits)); ::std::size_t input_distance { }; { local_input_iterator_type non_const_first = first; while(non_const_first != last) // NOLINT(altera-id-dependent-backward-branch) { ++non_const_first; ++input_distance; } } if(chunk_is_whole) { const auto copy_len = (detail::min_unsafe)(static_cast(val.crepresentation().size()), input_distance); if(msv_first) { detail::copy_unsafe(first, detail::advance_and_point(first, copy_len), local_result_iterator_type(detail::advance_and_point(val.representation().begin(), copy_len))); } else { using local_input_reverse_iterator_type = detail::iterator_detail::reverse_iterator; using local_difference_type = typename local_result_iterator_type::difference_type; detail::copy_unsafe(local_input_reverse_iterator_type(detail::advance_and_point(first, static_cast(input_distance))), local_input_reverse_iterator_type(detail::advance_and_point(first, static_cast(static_cast(input_distance) - static_cast(copy_len)))), local_result_iterator_type (detail::advance_and_point(val.representation().begin(), copy_len))); } detail::fill_unsafe(detail::advance_and_point(val.representation().begin(), copy_len), val.representation().end(), static_cast(UINT8_C(0))); } else { val = 0; const auto chunk_size_in = static_cast(chunk_size); const auto chunk_size_out = static_cast(std::numeric_limits::digits); const auto total_bits_input = static_cast ( static_cast(chunk_size_in) * input_distance ); const auto total_bits_to_use = (detail::min_unsafe) ( static_cast(total_bits_input), static_cast(std::numeric_limits::digits) ); const auto result_distance = static_cast ( static_cast(static_cast(total_bits_to_use) / chunk_size_out) + static_cast ( (static_cast(static_cast(total_bits_to_use) % chunk_size_out) != static_cast(UINT8_C(0))) ? static_cast(UINT8_C(1)) : static_cast(UINT8_C(0)) ) ); auto it_result = local_result_iterator_type(detail::advance_and_point(val.representation().begin(), result_distance)); if(msv_first) { detail::import_export_helper(first, it_result, total_bits_to_use, chunk_size_in, chunk_size_out); } else { using local_input_reverse_iterator_type = detail::iterator_detail::reverse_iterator; detail::import_export_helper(local_input_reverse_iterator_type(last), it_result, total_bits_to_use, chunk_size_in, chunk_size_out); } } return val; } template::value_type>::digits == std::numeric_limits::digits)> const*> constexpr auto import_bits(uintwide_t& val, ForwardIterator first, ForwardIterator last, unsigned chunk_size, bool msv_first) -> uintwide_t& { // This subroutine implements limb-by-limb import of bit-chunks. // This template specialization is intended for non-full chunk sizes, // whereby the width of the chunk's value type differs from the limb's width. // The order of bit-chunks imported is set by msv_first. using local_unsigned_wide_integer_type = uintwide_t; using local_result_iterator_type = typename local_unsigned_wide_integer_type::reverse_iterator; using local_result_value_type = typename local_result_iterator_type::value_type; using local_input_iterator_type = ForwardIterator; using local_input_value_type = typename detail::iterator_detail::iterator_traits::value_type; static_assert(std::numeric_limits::digits != std::numeric_limits::digits, "Error: Erroneous match for input element width and result uintwide_t limb width"); ::std::size_t input_distance { }; { local_input_iterator_type non_const_first = first; while(non_const_first != last) // NOLINT(altera-id-dependent-backward-branch) { ++non_const_first; ++input_distance; } } val = 0; if(chunk_size == static_cast(UINT8_C(0))) { chunk_size = static_cast(std::numeric_limits::digits); } chunk_size = (detail::min_unsafe)(static_cast(std::numeric_limits::digits), chunk_size); const auto chunk_size_in = static_cast(chunk_size); const auto chunk_size_out = static_cast(std::numeric_limits::digits); const auto total_bits_input = static_cast ( static_cast(chunk_size_in) * input_distance ); const auto total_bits_to_use = (detail::min_unsafe) ( static_cast(total_bits_input), static_cast(std::numeric_limits::digits) ); const auto result_distance = static_cast ( static_cast(static_cast(total_bits_to_use) / chunk_size_out) + static_cast ( (static_cast(static_cast(total_bits_to_use) % chunk_size_out) != static_cast(UINT8_C(0))) ? static_cast(UINT8_C(1)) : static_cast(UINT8_C(0)) ) ); auto it_result = local_result_iterator_type(detail::advance_and_point(val.representation().begin(), result_distance)); if(msv_first) { detail::import_export_helper(first, it_result, total_bits_to_use, chunk_size_in, chunk_size_out); } else { using local_input_reverse_iterator_type = detail::iterator_detail::reverse_iterator; detail::import_export_helper(local_input_reverse_iterator_type(last), it_result, total_bits_to_use, chunk_size_in, chunk_size_out); } return val; } template::value_type>::digits == std::numeric_limits::digits> const*> constexpr auto export_bits(const uintwide_t& val, OutputIterator out, unsigned chunk_size, bool msv_first) -> OutputIterator { // This subroutine implements limb-by-limb export of bit-chunks. // This template specialization is intended for full chunk sizes, // whereby the width of the chunk's value type equals the limb's width. // If, however, the chunk_size to export is not "full", then this // subroutine uses slow bit-by-bit methods. // The order of bit-chunks exported is set by msv_first. using local_unsigned_wide_integer_type = uintwide_t; using local_result_iterator_type = OutputIterator; using local_result_value_type = typename detail::iterator_detail::iterator_traits::value_type; using local_input_value_type = typename local_unsigned_wide_integer_type::representation_type::value_type; local_unsigned_wide_integer_type val_unsigned(val); if(uintwide_t::is_neg(val)) { val_unsigned.negate(); } static_assert(std::numeric_limits::digits == std::numeric_limits::digits, "Error: Erroneous mismatch for input element width and result uintwide_t limb width"); chunk_size = (detail::min_unsafe)(static_cast(std::numeric_limits::digits), chunk_size); const auto chunk_size_in = static_cast(std::numeric_limits::digits); const auto chunk_size_out = chunk_size; const auto msb_plus_one = static_cast(msb(val_unsigned) + static_cast(UINT8_C(1))); const auto input_distance_chunk_size_has_mod = (static_cast(msb_plus_one % chunk_size_in) != static_cast(UINT8_C(0))); const auto input_distance = static_cast ( static_cast(msb_plus_one / chunk_size_in) + static_cast ( input_distance_chunk_size_has_mod ? static_cast(UINT8_C(1)) : static_cast(UINT8_C(0)) ) ); const auto chunk_is_whole = (chunk_size == static_cast(std::numeric_limits::digits)); using local_input_const_reverse_iterator_type = detail::iterator_detail::reverse_iterator; if(chunk_is_whole) { if(msv_first) { out = detail::copy_unsafe(local_input_const_reverse_iterator_type(detail::advance_and_point(val.representation().cbegin(), input_distance)), val.representation().crend(), out); } else { out = detail::copy_unsafe(val.representation().cbegin(), detail::advance_and_point(val.representation().cbegin(), input_distance), out); } } else { if(msv_first) { out = detail::import_export_helper(local_input_const_reverse_iterator_type(detail::advance_and_point(val_unsigned.crepresentation().cbegin(), input_distance)), out, static_cast(msb_plus_one), chunk_size_in, chunk_size_out) + static_cast(UINT8_C(1)); } else { const auto output_distance_chunk_size_has_mod = (static_cast(msb_plus_one % chunk_size_out) != static_cast(UINT8_C(0))); const auto output_distance = static_cast ( static_cast(msb_plus_one / chunk_size_out) + static_cast ( output_distance_chunk_size_has_mod ? static_cast(UINT8_C(1)) : static_cast(UINT8_C(0)) ) ); using local_result_reverse_iterator_type = detail::iterator_detail::reverse_iterator; static_cast(detail::import_export_helper(local_input_const_reverse_iterator_type (detail::advance_and_point(val_unsigned.crepresentation().cbegin(), input_distance)), local_result_reverse_iterator_type(detail::advance_and_point(out, output_distance)), // LCOV_EXCL_LINE static_cast(msb_plus_one), chunk_size_in, chunk_size_out)); using result_difference_type = typename detail::iterator_detail::iterator_traits::difference_type; out += static_cast(output_distance); } } return out; } template::value_type>::digits == std::numeric_limits::digits)> const*> constexpr auto export_bits(const uintwide_t& val, OutputIterator out, unsigned chunk_size, bool msv_first) -> OutputIterator { // This subroutine implements limb-by-limb export of bit-chunks. // This template specialization is intended for non-full chunk sizes, // whereby the width of the chunk's value type differs from the limb's width. // The order of bit-chunks exported is set by msv_first. using local_unsigned_wide_integer_type = uintwide_t; using local_result_iterator_type = OutputIterator; using local_result_value_type = typename detail::iterator_detail::iterator_traits::value_type; using local_input_value_type = typename local_unsigned_wide_integer_type::representation_type::value_type; local_unsigned_wide_integer_type val_unsigned(val); if(uintwide_t::is_neg(val)) { val_unsigned.negate(); } static_assert(std::numeric_limits::digits != std::numeric_limits::digits, "Error: Erroneous match for input element width and result uintwide_t limb width"); chunk_size = (detail::min_unsafe)(static_cast(std::numeric_limits::digits), chunk_size); const auto chunk_size_in = static_cast(std::numeric_limits::digits); const auto chunk_size_out = chunk_size; const auto msb_plus_one = static_cast(msb(val_unsigned) + static_cast(UINT8_C(1))); const auto input_distance_chunk_size_has_mod = (static_cast(msb_plus_one % chunk_size_in) != static_cast(UINT8_C(0))); const auto input_distance = static_cast ( static_cast(msb_plus_one / chunk_size_in) + static_cast ( input_distance_chunk_size_has_mod ? static_cast(UINT8_C(1)) : static_cast(UINT8_C(0)) ) ); using local_input_const_reverse_iterator_type = typename local_unsigned_wide_integer_type::representation_type::const_reverse_iterator; if(msv_first) { out = detail::import_export_helper ( local_input_const_reverse_iterator_type(detail::advance_and_point(val_unsigned.crepresentation().cbegin(), input_distance)), out, static_cast(msb_plus_one), chunk_size_in, chunk_size_out ); ++out; } else { const auto output_distance_chunk_size_has_mod = (static_cast(msb_plus_one % chunk_size_out) != static_cast(UINT8_C(0))); const auto output_distance = static_cast ( static_cast(msb_plus_one / chunk_size_out) + static_cast ( output_distance_chunk_size_has_mod ? static_cast(UINT8_C(1)) : static_cast(UINT8_C(0)) ) ); using local_result_reverse_iterator_type = detail::iterator_detail::reverse_iterator; static_cast ( detail::import_export_helper ( local_input_const_reverse_iterator_type(detail::advance_and_point(val_unsigned.crepresentation().cbegin(), input_distance)), local_result_reverse_iterator_type (detail::advance_and_point(out, output_distance)), static_cast(msb_plus_one), chunk_size_in, chunk_size_out ) ); using result_difference_type = typename detail::iterator_detail::iterator_traits::difference_type; out += static_cast(output_distance); } return out; } #if(__cplusplus >= 201703L) } // namespace math::wide_integer #else } // namespace wide_integer } // namespace math #endif WIDE_INTEGER_NAMESPACE_END #endif // UINTWIDE_T_2018_10_02_H ================================================ FILE: run_fuzzing.sh ================================================ #!/usr/bin/env bash # # Copyright Christopher Kormanyos 2024 - 2026. # Distributed under the Boost Software License, # Version 1.0. (See accompanying file LICENSE_1_0.txt # or copy at http://www.boost.org/LICENSE_1_0.txt) # # Example call: # bash run_fuzzing.sh /mnt/c/boost/boost_1_90_0 if [[ "$1" != "" ]]; then MY_BOOST="$1" else MY_BOOST=../boost-root fi echo 'compiling test/fuzzing/test_fuzzing_add.cpp' && clang++ -std=c++20 -g -O2 -Wall -Wextra -fsanitize=fuzzer -I. -I$MY_BOOST test/fuzzing/test_fuzzing_add.cpp -o test_fuzzing_add echo 'compiling test/fuzzing/test_fuzzing_sub.cpp' && clang++ -std=c++20 -g -O2 -Wall -Wextra -fsanitize=fuzzer -I. -I$MY_BOOST test/fuzzing/test_fuzzing_sub.cpp -o test_fuzzing_sub echo 'compiling test/fuzzing/test_fuzzing_mul.cpp' && clang++ -std=c++20 -g -O2 -Wall -Wextra -fsanitize=fuzzer -I. -I$MY_BOOST test/fuzzing/test_fuzzing_mul.cpp -o test_fuzzing_mul echo 'compiling test/fuzzing/test_fuzzing_div.cpp' && clang++ -std=c++20 -g -O2 -Wall -Wextra -fsanitize=fuzzer -I. -I$MY_BOOST test/fuzzing/test_fuzzing_div.cpp -o test_fuzzing_div echo 'compiling test/fuzzing/test_fuzzing_sdiv.cpp' && clang++ -std=c++20 -g -O2 -Wall -Wextra -fsanitize=fuzzer -I. -I$MY_BOOST test/fuzzing/test_fuzzing_sdiv.cpp -o test_fuzzing_sdiv echo 'compiling test/fuzzing/test_fuzzing_sqrt.cpp' && clang++ -std=c++20 -g -O2 -Wall -Wextra -fsanitize=fuzzer -I. -I$MY_BOOST test/fuzzing/test_fuzzing_sqrt.cpp -o test_fuzzing_sqrt echo 'compiling test/fuzzing/test_fuzzing_powm.cpp' && clang++ -std=c++20 -g -O2 -Wall -Wextra -fsanitize=fuzzer -I. -I$MY_BOOST test/fuzzing/test_fuzzing_powm.cpp -o test_fuzzing_powm echo 'compiling test/fuzzing/test_fuzzing_prime.cpp' && clang++ -std=c++20 -g -O2 -Wall -Wextra -fsanitize=fuzzer -I. -I$MY_BOOST test/fuzzing/test_fuzzing_prime.cpp -o test_fuzzing_prime ls -la test_fuzzing_add test_fuzzing_sub test_fuzzing_mul test_fuzzing_div test_fuzzing_sdiv test_fuzzing_sqrt test_fuzzing_powm test_fuzzing_prime exit_compile=$? rnd_seed=-seed=$(($(date +%s%N) % 4294967295)) echo echo seed is $rnd_seed echo # Start each executable in the background and save their process IDs ./test_fuzzing_add -max_total_time=900 -max_len=66 -verbosity=0 -close_fd_mask=3 $rnd_seed & pid_add=$! ./test_fuzzing_sub -max_total_time=900 -max_len=66 -verbosity=0 -close_fd_mask=3 $rnd_seed & pid_sub=$! ./test_fuzzing_mul -max_total_time=900 -max_len=66 -verbosity=0 -close_fd_mask=3 $rnd_seed & pid_mul=$! ./test_fuzzing_div -max_total_time=900 -max_len=66 -verbosity=0 -close_fd_mask=3 $rnd_seed & pid_div=$! ./test_fuzzing_sdiv -max_total_time=900 -max_len=66 -verbosity=0 -close_fd_mask=3 $rnd_seed & pid_sdiv=$! ./test_fuzzing_sqrt -max_total_time=900 -max_len=34 -verbosity=0 -close_fd_mask=3 $rnd_seed & pid_sqrt=$! ./test_fuzzing_powm -max_total_time=900 -max_len=98 -verbosity=0 -close_fd_mask=3 $rnd_seed & pid_powm=$! ./test_fuzzing_prime -max_total_time=900 -max_len=34 -verbosity=0 -close_fd_mask=3 $rnd_seed & pid_prime=$! # Wait for each job and capture its exit status wait $pid_add exit_add=$? wait $pid_sub exit_sub=$? wait $pid_mul exit_mul=$? wait $pid_div exit_div=$? wait $pid_sdiv exit_sdiv=$? wait $pid_sqrt exit_sqrt=$? wait $pid_powm exit_powm=$? wait $pid_prime exit_prime=$? # Check the status of compilation and of each executable echo "exit_compile : " "$exit_compile" echo "exit_add : " "$exit_add" echo "exit_sub : " "$exit_sub" echo "exit_mul : " "$exit_mul" echo "exit_div : " "$exit_div" echo "exit_sdiv : " "$exit_sdiv" echo "exit_sqrt : " "$exit_sqrt" echo "exit_powm : " "$exit_powm" echo "exit_prime : " "$exit_prime" result_total=$((exit_compile+exit_add+exit_sub+exit_mul+exit_div+exit_sdiv+exit_sqrt+exit_powm+exit_prime)) echo "result_total : " "$result_total" exit $result_total ================================================ FILE: sonar-project.properties ================================================ sonar.organization=ckormanyos sonar.projectKey=ckormanyos_wide-integer # This is the name and version displayed in the SonarCloud UI. sonar.projectName=wide-integer sonar.projectVersion=1.0 # Path is relative to the sonar-project.properties file. Replace "\" by "/" on Windows. sonar.sources=. # Encoding of the source code. Default is default system encoding #sonar.sourceEncoding=UTF-8 ================================================ FILE: target/build/test_examples_emulator.gdb ================================================ # /////////////////////////////////////////////////////////////////// # // Copyright Christopher Kormanyos 2020 - 2025. # // Distributed under the Boost Software License, # // Version 1.0. (See accompanying file LICENSE_1_0.txt # // or copy at http://www.boost.org/LICENSE_1_0.txt) # // # Connect to the target (e.g., OpenOCD or another GDB server). target remote localhost:9999 monitor halt # Ensure that the program is loaded. load # Set a breakpoint at the specified subroutine. break example_get_standalone_result # Start or continue program execution. continue # Format and print the value of a variable. printf "value 0x%X\n\n", example_standalone_result # Delete (all) breakpoint(s). delete # Perform a non-elegant quit of the GDB session. quit ================================================ FILE: target/micros/stm32f429/make/single/crt.cpp ================================================ /////////////////////////////////////////////////////////////////////////////// // Copyright Christopher Kormanyos 2018 - 2025. // Distributed under the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt // or copy at http://www.boost.org/LICENSE_1_0.txt) // #if defined(__GNUC__) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Warray-bounds" #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wstringop-overflow=" #endif #include #include #include #include #include #include // STM32 EABI ARM(R) Cortex-M4(TM) startup code. // Expressed with C++ for STM32Fx by Chris. // C:\Users\User\Documents\Ks\uC_Software\Boards\real-time-cpp\ref_app\tools\Util\MinGW\msys\1.0\local\gcc-9.3.1-arm-none-eabi\bin\arm-none-eabi-g++ -std=c++14 -Wall -Wextra -pedantic -O2 -g -gdwarf-2 -fno-exceptions -ffunction-sections -fdata-sections -x c++ -fno-rtti -fno-use-cxa-atexit -fno-exceptions -fno-nonansi-builtins -fno-threadsafe-statics -fno-enforce-eh-specs -ftemplate-depth=32 -mcpu=cortex-m4 -mtune=cortex-m4 -mthumb -mfloat-abi=soft -mno-unaligned-access -mno-long-calls -I./src/mcal/stm32f446 -I./src -DAPP_BENCHMARK_TYPE=APP_BENCHMARK_TYPE_CRC -DAPP_BENCHMARK_STANDALONE_MAIN ./src/app/benchmark/app_benchmark_crc.cpp ./target/micros/stm32f446/make/single/crt.cpp -nostartfiles -Wl,--gc-sections -Wl,-Map,./bin/app_benchmark_crc.map -T ./target/micros/stm32f446/make/stm32f446.ld -o ./bin/app_benchmark_crc.elf namespace crt { void init_ram(); } namespace crt { void init_ctors(); } extern "C" void __my_startup(void) __attribute__((used, noinline)); void __my_startup(void) { // Load the stack pointer. // The stack pointer is automatically loaded from // the base position of the interrupt vector table. // So we do nothing here. // Note: Not needed: // Chip init: Watchdog, port, and oscillator, if any needed. // Initialize statics from ROM to RAM. // Zero-clear default-initialized static RAM. crt::init_ram(); // Call all ctor initializations. crt::init_ctors(); // Jump to main (and never return). asm volatile("ldr r3, =main"); asm volatile("blx r3"); // Do nothing on return from main. } extern "C" void _exit (int); extern "C" void _exit (int) { } extern "C" { extern std::uintptr_t _rom_data_begin; // Start address for the initialization values of the rom-to-ram section. extern std::uintptr_t _data_begin; // Start address for the .data section. extern std::uintptr_t _data_end; // End address for the .data section. extern std::uintptr_t _bss_begin; // Start address for the .bss section. extern std::uintptr_t _bss_end; // End address for the .bss section. } void crt::init_ram() { using memory_aligned_type = ::std::uint32_t; // Copy the data segment initializers from ROM to RAM. // Note that all data segments are aligned by 4. const std::size_t size_data = std::size_t( static_cast(static_cast(&_data_end)) - static_cast(static_cast(&_data_begin))); std::copy(static_cast(static_cast(&_rom_data_begin)), static_cast(static_cast(&_rom_data_begin)) + size_data, static_cast< memory_aligned_type*>(static_cast< void*>(&_data_begin))); // Clear the bss segment. // Note that the bss segment is aligned by 4. std::fill(static_cast(static_cast(&_bss_begin)), static_cast(static_cast(&_bss_end)), static_cast(0U)); } extern "C" { struct ctor_type { using function_type = void(*)(); using const_reverse_iterator = std::reverse_iterator; }; extern ctor_type::function_type _ctors_end[]; extern ctor_type::function_type _ctors_begin[]; } void crt::init_ctors() { std::for_each(ctor_type::const_reverse_iterator(_ctors_end), ctor_type::const_reverse_iterator(_ctors_begin), [](const ctor_type::function_type pf) { pf(); }); } extern "C" void __initial_stack_pointer(); extern "C" void __my_startup () __attribute__((used, noinline)); extern "C" void __vector_unused_irq () __attribute__((used, noinline)); extern "C" void __nmi_handler () __attribute__((used, noinline)); extern "C" void __hard_fault_handler () __attribute__((used, noinline)); extern "C" void __mem_manage_handler () __attribute__((used, noinline)); extern "C" void __bus_fault_handler () __attribute__((used, noinline)); extern "C" void __usage_fault_handler() __attribute__((used, noinline)); extern "C" void __svc_handler () __attribute__((used, noinline)); extern "C" void __debug_mon_handler () __attribute__((used, noinline)); extern "C" void __pend_sv_handler () __attribute__((used, noinline)); extern "C" void __sys_tick_handler () __attribute__((used, noinline)); extern "C" void __vector_unused_irq () { for(;;) { ; } } extern "C" void __nmi_handler () { for(;;) { ; } } extern "C" void __hard_fault_handler () { for(;;) { ; } } extern "C" void __mem_manage_handler () { for(;;) { ; } } extern "C" void __bus_fault_handler () { for(;;) { ; } } extern "C" void __usage_fault_handler() { for(;;) { ; } } extern "C" void __svc_handler () { for(;;) { ; } } extern "C" void __debug_mon_handler () { for(;;) { ; } } extern "C" void __pend_sv_handler () { for(;;) { ; } } extern "C" void __sys_tick_handler () { for(;;) { ; } } namespace { using isr_type = void(*)(); constexpr std::size_t number_of_interrupts = 128U; } extern "C" const volatile std::array __isr_vector __attribute__((section(".isr_vector"))); extern "C" const volatile std::array __isr_vector = {{ __initial_stack_pointer, // 0x0000, initial stack pointer __my_startup, // 0x0004, reset __nmi_handler, // 0x0008, nmi exception __hard_fault_handler, // 0x000C, hard fault exception __mem_manage_handler, // 0x0010, memory management exception __bus_fault_handler, // 0x0014, bus fault exception __usage_fault_handler, // 0x0018, usage fault exception __vector_unused_irq, // 0x001C, reserved __vector_unused_irq, // 0x0020, reserved __vector_unused_irq, // 0x0024, reserved __vector_unused_irq, // 0x0028, reserved __svc_handler, // 0x002C, svc handler __debug_mon_handler, // 0x0030, debug monitor __vector_unused_irq, // 0x0034, reserved __pend_sv_handler, // 0x0038, pending svc, __sys_tick_handler, // 0x003C, system tick handler, __vector_unused_irq, // 0x0040, wwdg irq handler, __vector_unused_irq, // 0x0044, pvd irq handler, __vector_unused_irq, // 0x0048, tamper irq handler, __vector_unused_irq, // 0x004C, rtc irq handler, __vector_unused_irq, // 0x0050, flash irq handler, __vector_unused_irq, // 0x0054, rcc irq handler, __vector_unused_irq, // 0x0058, exti0 irq handler, __vector_unused_irq, // 0x005C, exti1 irq handler, __vector_unused_irq, // 0x0060, exti2 irq handler, __vector_unused_irq, // 0x0064, exti3 irq handler, __vector_unused_irq, // 0x0068, exti4 irq handler, __vector_unused_irq, // 0x006C, dma_channel1 irq handler, __vector_unused_irq, // 0x0070, dma_channel2 irq handler, __vector_unused_irq, // 0x0074, dma_channel3 irq handler, __vector_unused_irq, // 0x0078, dma_channel4 irq handler, __vector_unused_irq, // 0x007C, dma_channel5 irq handler, __vector_unused_irq, // 0x0080, dma_channel6 irq handler, __vector_unused_irq, // 0x0084, dma_channel7 irq handler, __vector_unused_irq, // 0x0088, adc irq handler, __vector_unused_irq, // 0x008C, usb_hp_can_tx irq handler, __vector_unused_irq, // 0x0090, usb_lp_can_rx0 irq handler, __vector_unused_irq, // 0x0094, can_rx1 irq handler, __vector_unused_irq, // 0x0098, can_sce irq handler, __vector_unused_irq, // 0x009C, exti9_5 irq handler, __vector_unused_irq, // 0x00A0, tim1_brk irq handler, __vector_unused_irq, // 0x00A4, tim1_up irq handler, __vector_unused_irq, // 0x00A8, tim1_trg_com irq handler, __vector_unused_irq, // 0x00AC, tim1_cc irq handler, __vector_unused_irq, // 0x00B0, tim2 irq handler, __vector_unused_irq, // 0x00B4, tim3 irq handler, __vector_unused_irq, // 0x00B8, tim4 irq handler, __vector_unused_irq, // 0x00BC, i2c1_ev irq handler, __vector_unused_irq, // 0x00C0, i2c1_er irq handler, __vector_unused_irq, // 0x00C4, i2c2_ev irq handler, __vector_unused_irq, // 0x00C8, i2c2_er irq handler, __vector_unused_irq, // 0x00CC, spi1 irq handler, __vector_unused_irq, // 0x00D0, spi2 irq handler, __vector_unused_irq, // 0x00D4, usart1 irq handler, __vector_unused_irq, // 0x00D8, usart2 irq handler, __vector_unused_irq, // 0x00DC, usart3 irq handler, __vector_unused_irq, // 0x00E0, exti15_10 irq handler, __vector_unused_irq, // 0x00E4, rtcalarm irq handler, __vector_unused_irq, // 0x00E8, usbwakeup irq handler, __vector_unused_irq, // 0x00EC, tim8 break and tim12 __vector_unused_irq, // 0x00F0, tim8 update and tim13 __vector_unused_irq, // 0x00F4, tim8 trigger and commutation and tim14 __vector_unused_irq, // 0x00F8, tim8 capture compare __vector_unused_irq, // 0x00FC, dma1 stream7 __vector_unused_irq, // 0x0100, fmc __vector_unused_irq, // 0x0104, sdio __vector_unused_irq, // 0x0108, tim5 __vector_unused_irq, // 0x010C, spi3 __vector_unused_irq, // 0x0110, uart4 __vector_unused_irq, // 0x0114, uart5 __vector_unused_irq, // 0x0118, tim6 and dac1&2 underrun errors __vector_unused_irq, // 0x011C, tim7 __vector_unused_irq, // 0x0120, dma2 stream 0 __vector_unused_irq, // 0x0124, dma2 stream 1 __vector_unused_irq, // 0x0128, dma2 stream 2 __vector_unused_irq, // 0x012C, dma2 stream 3 __vector_unused_irq, // 0x0130, dma2 stream 4 __vector_unused_irq, // 0x0134, ethernet __vector_unused_irq, // 0x0138, ethernet wakeup through exti line __vector_unused_irq, // 0x013C, can2 tx __vector_unused_irq, // 0x0140, can2 rx0 __vector_unused_irq, // 0x0144, can2 rx1 __vector_unused_irq, // 0x0148, can2 sce __vector_unused_irq, // 0x014C, usb otg fs __vector_unused_irq, // 0x0150, dma2 stream 5 __vector_unused_irq, // 0x0154, dma2 stream 6 __vector_unused_irq, // 0x0158, dma2 stream 7 __vector_unused_irq, // 0x015C, usart6 __vector_unused_irq, // 0x0160, i2c3 event __vector_unused_irq, // 0x0164, i2c3 error __vector_unused_irq, // 0x0168, usb otg hs end point 1 out __vector_unused_irq, // 0x016C, usb otg hs end point 1 in __vector_unused_irq, // 0x0170, usb otg hs wakeup through exti __vector_unused_irq, // 0x0174, usb otg hs __vector_unused_irq, // 0x0178, dcmi __vector_unused_irq, // 0x017C, cryp crypto __vector_unused_irq, // 0x0180, hash and rng __vector_unused_irq, // 0x0184, fpu __vector_unused_irq, // 0x0188, uart7 __vector_unused_irq, // 0x018C, uart8 __vector_unused_irq, // 0x0190, spi4 __vector_unused_irq, // 0x0194, spi5 __vector_unused_irq, // 0x0198, spi6 __vector_unused_irq, // 0x019C, sai1 __vector_unused_irq, // 0x01A0, reserved __vector_unused_irq, // 0x01A4, reserved __vector_unused_irq, // 0x01A8, dma2d nullptr, // 0x01AC, dummy nullptr, // 0x01B0, dummy nullptr, // 0x01B4, dummy nullptr, // 0x01B8, dummy nullptr, // 0x01BC, dummy nullptr, // 0x01C0, dummy nullptr, // 0x01C4, dummy nullptr, // 0x01C8, dummy nullptr, // 0x01CC, dummy nullptr, // 0x01D0, dummy nullptr, // 0x01D4, dummy nullptr, // 0x01D8, dummy nullptr, // 0x01DC, dummy nullptr, // 0x01E0, dummy nullptr, // 0x01E4, dummy nullptr, // 0x01E8, dummy nullptr, // 0x01EC, dummy nullptr, // 0x01F0, dummy nullptr, // 0x01F4, dummy nullptr, // 0x01F8, dummy nullptr // 0x01FC, dummy }}; #if defined(__GNUC__) #pragma GCC diagnostic pop #pragma GCC diagnostic pop #endif ================================================ FILE: target/micros/stm32f429/make/stm32f429.ld ================================================ /* Copyright Christopher Kormanyos 2007 - 2025. Distributed under the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) */ /* Linker script for STM32F4xx ARM(R) Cortex(TM)-M4 MCU */ ENTRY(__my_startup) INPUT(libc.a libm.a libgcc.a) OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm") OUTPUT_ARCH(arm) /* The beginning and end of the program ROM area */ /* Set up a ROM area with a size of 64K */ _rom_begin = 0x08000000; _rom_end = 0x08010000; /* The beginning and end (i.e., the top) of the stack */ /* Set up a stack with a size of 4K */ _stack_begin = 0x20007000; _stack_end = 0x20008000; __initial_stack_pointer = 0x20008000 - 4; MEMORY { ROM(rx) : ORIGIN = 0x08000000, LENGTH = 64K RAM(rwx) : ORIGIN = 0x20000000, LENGTH = 0x7000 } SECTIONS { . = 0x08000000; . = ALIGN(4); /* ISR vectors */ .isr_vector : { *(.isr_vector) . = ALIGN(0x10); KEEP(*(.isr_vector)) } > ROM = 0xAAAA /* startup */ .startup : { *(.startup) . = ALIGN(0x10); KEEP(*(.startup)) } > ROM = 0x5555 /* Program code (text), read-only data and static ctors */ .text : { _ctors_begin = .; KEEP(*(SORT(.init_array.*))) KEEP(*(.init_array*)) _ctors_end = .; *(.progmem*) . = ALIGN(4); *(.text) . = ALIGN(4); *(.text*) . = ALIGN(4); *(.rodata) . = ALIGN(4); *(.rodata*) . = ALIGN(4); *(.glue_7) . = ALIGN(4); *(.glue_7t) . = ALIGN(4); } > ROM .ARM.extab : { . = ALIGN(4); *(.ARM.extab) *(.gnu.linkonce.armextab.*) . = ALIGN(4); } > ROM .exidx : { . = ALIGN(4); PROVIDE(__exidx_start = .); *(.ARM.exidx*) . = ALIGN(4); PROVIDE(__exidx_end = .); } > ROM .ARM.attributes : { *(.ARM.attributes) } > ROM . = 0x20000000; . = ALIGN(4); /* The ROM-to-RAM initialized data section */ .data : { _data_begin = .; *(.data) . = ALIGN(4); KEEP (*(.data)) *(.data*) . = ALIGN(4); KEEP (*(.data*)) _data_end = .; } > RAM AT > ROM /* The uninitialized (zero-cleared) data section */ .bss : { _bss_begin = .; *(.bss) . = ALIGN(4); KEEP (*(.bss)) *(.bss*) . = ALIGN(4); KEEP (*(.bss*)) _bss_end = .; } > RAM PROVIDE(end = .); PROVIDE(_fini = .); _rom_data_begin = LOADADDR(.data); } ================================================ FILE: test/CMakeLists.txt ================================================ enable_testing() find_package(Threads) if (Boost_FOUND) add_executable(test_uintwide_t test_uintwide_t_boost_backend.cpp test_uintwide_t_edge_cases.cpp test_uintwide_t_examples.cpp test_uintwide_t_float_convert.cpp test_uintwide_t_int_convert.cpp test_uintwide_t_n_base.cpp test_uintwide_t_n_binary_ops_base.cpp test_uintwide_t_spot_values.cpp test.cpp) target_compile_features(test_uintwide_t PRIVATE cxx_std_20) target_include_directories(test_uintwide_t PRIVATE ${PROJECT_SOURCE_DIR}) target_link_libraries(test_uintwide_t Examples ${CMAKE_THREAD_LIBS_INIT}) add_test(test test_uintwide_t) endif() ================================================ FILE: test/coverity.c ================================================ /* Coverity Scan model */ void dummy(void) { } ================================================ FILE: test/fuzzing/test_fuzzing_add.cpp ================================================ /////////////////////////////////////////////////////////////////////////////// // Copyright Christopher Kormanyos 2024 - 2026. // Distributed under the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt // or copy at http://www.boost.org/LICENSE_1_0.txt) // // cd /mnt/c/Users/ckorm/Documents/Ks/PC_Software/NumericalPrograms/ExtendedNumberTypes/wide_integer // clang++ -std=c++20 -g -O2 -Wall -Wextra -fsanitize=fuzzer -I. -I/mnt/c/boost/boost_1_90_0 test/fuzzing/test_fuzzing_add.cpp -o test_fuzzing_add // ./test_fuzzing_add -max_total_time=300 #include #include #include #include #include #include #include namespace fuzzing { using boost_uint_backend_type = boost::multiprecision::cpp_int_backend(UINT32_C(256)), static_cast(UINT32_C(256)), boost::multiprecision::unsigned_magnitude>; using boost_uint_type = boost::multiprecision::number; using local_uint_type = ::math::wide_integer::uint256_t; auto eval_op(const std::uint8_t* data, std::size_t size) -> bool; } auto fuzzing::eval_op(const std::uint8_t* data, std::size_t size) -> bool { const std::size_t max_size { static_cast ( std::numeric_limits::digits / 8 ) }; bool result_is_ok { true }; size = (std::min)(size, std::size_t { max_size * 2U }); if(size > std::size_t { UINT8_C(1) }) { local_uint_type a_local { 0U }; local_uint_type b_local { 0U }; boost_uint_type a_boost { 0U }; boost_uint_type b_boost { 0U }; // Import data into the uintwide_t values. import_bits ( a_local, data, data + std::size_t { size / 2U }, 8U ); import_bits ( b_local, data + std::size_t { size / 2U }, data + size, 8U ); // Import data into the boost values. import_bits ( a_boost, data, data + std::size_t { size / 2U }, 8U ); import_bits ( b_boost, data + std::size_t { size / 2U }, data + size, 8U ); local_uint_type result_local { a_local + b_local }; boost_uint_type result_boost { a_boost + b_boost }; std::vector result_data_local(max_size, UINT8_C(0)); std::vector result_data_boost(result_data_local.size(), UINT8_C(0)); export_bits(result_local, result_data_local.data(), 8U); export_bits(result_boost, result_data_boost.data(), 8U); // Verify that both uintwide_t as well as boost obtain the same result. const bool result_op_is_ok = std::equal ( result_data_local.cbegin(), result_data_local.cend(), result_data_boost.cbegin(), result_data_boost.cend() ); result_is_ok = (result_op_is_ok && result_is_ok); } // Assert the correct result. assert(result_is_ok); return result_is_ok; } // The fuzzing entry point. extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { const bool result_one_add_is_ok { fuzzing::eval_op(data, size) }; return (result_one_add_is_ok ? 0 : -1); } ================================================ FILE: test/fuzzing/test_fuzzing_div.cpp ================================================ /////////////////////////////////////////////////////////////////////////////// // Copyright Christopher Kormanyos 2024 - 2026. // Distributed under the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt // or copy at http://www.boost.org/LICENSE_1_0.txt) // // cd /mnt/c/Users/ckorm/Documents/Ks/PC_Software/NumericalPrograms/ExtendedNumberTypes/wide_integer // clang++ -std=c++20 -g -O2 -Wall -Wextra -fsanitize=fuzzer -I. -I/mnt/c/boost/boost_1_90_0 test/fuzzing/test_fuzzing_div.cpp -o test_fuzzing_div // ./test_fuzzing_div -max_total_time=300 #include #include #include #include #include #include #include namespace fuzzing { using boost_uint_backend_type = boost::multiprecision::cpp_int_backend(UINT32_C(256)), static_cast(UINT32_C(256)), boost::multiprecision::unsigned_magnitude>; using boost_uint_type = boost::multiprecision::number; using local_uint_type = ::math::wide_integer::uint256_t; auto eval_op(const std::uint8_t* data, std::size_t size) -> bool; } auto fuzzing::eval_op(const std::uint8_t* data, std::size_t size) -> bool { const std::size_t max_size { static_cast ( std::numeric_limits::digits / 8 ) }; bool result_is_ok { true }; size = (std::min)(size, std::size_t { max_size * 2U }); if(size > std::size_t { UINT8_C(1) }) { local_uint_type a_local { 0U }; local_uint_type b_local { 0U }; boost_uint_type a_boost { 0U }; boost_uint_type b_boost { 0U }; // Import data into the uintwide_t values. import_bits ( a_local, data, data + std::size_t { size / 2U }, 8U ); import_bits ( b_local, data + std::size_t { size / 2U }, data + size, 8U ); // Import data into the boost values. import_bits ( a_boost, data, data + std::size_t { size / 2U }, 8U ); import_bits ( b_boost, data + std::size_t { size / 2U }, data + size, 8U ); if(a_local < b_local) { std::swap(a_local, b_local); std::swap(a_boost, b_boost); } if(b_local != 0U) { local_uint_type result_local { a_local / b_local }; boost_uint_type result_boost { a_boost / b_boost }; std::vector result_data_local(max_size, UINT8_C(0)); std::vector result_data_boost(result_data_local.size(), UINT8_C(0)); export_bits(result_local, result_data_local.data(), 8U); export_bits(result_boost, result_data_boost.data(), 8U); // Verify that both uintwide_t as well as boost obtain the same result. const bool result_op_is_ok = std::equal ( result_data_local.cbegin(), result_data_local.cend(), result_data_boost.cbegin(), result_data_boost.cend() ); result_is_ok = (result_op_is_ok && result_is_ok); } } // Assert the correct result. assert(result_is_ok); return result_is_ok; } // The fuzzing entry point. extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { const bool result_one_div_is_ok { fuzzing::eval_op(data, size) }; return (result_one_div_is_ok ? 0 : -1); } ================================================ FILE: test/fuzzing/test_fuzzing_div_versus_cppalliance_int128.cpp ================================================ /////////////////////////////////////////////////////////////////////////////// // Copyright Matt Borland 2024 - 2025. // Copyright Christopher Kormanyos 2024 - 2026. // Distributed under the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt // or copy at http://www.boost.org/LICENSE_1_0.txt) // // cd /mnt/c/Users/ckorm/Documents/Ks/PC_Software/NumericalPrograms/ExtendedNumberTypes/wide_integer // clang++ -std=c++20 -g -O2 -Wall -Wextra -Wpedantic -Wconversion -Wsign-conversion -fsanitize=fuzzer -I. -I/mnt/c/ChrisGitRepos/cppalliance/int128/include -I../NumericalPrograms/ExtendedNumberTypes/wide_integer test/fuzzing/test_fuzzing_div_versus_cppalliance_int128.cpp -o test_fuzzing_div_versus_cppalliance_int128 // ./test_fuzzing_div_versus_cppalliance_int128 -max_total_time=1200 -max_len=32 #include #include #include #include #include #include #include #include #include extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size); namespace fuzzing { template auto eval_op(const CntrlUintType& a_cntrl, const CntrlUintType& b_cntrl, const LocalUintType& a_local, const LocalUintType& b_local) -> bool; } template auto fuzzing::eval_op(const CntrlUintType& a_cntrl, const CntrlUintType& b_cntrl, const LocalUintType& a_local, const LocalUintType& b_local) -> bool { using cntrl_uint_type = CntrlUintType; using local_uint_type = LocalUintType; static_assert ( (std::numeric_limits::digits == std::numeric_limits::digits) && (std::numeric_limits::digits == int { INT32_C(128) }), "Error: the control and local types must both have 128 binary digits" ); const local_uint_type result_local { local_uint_type(a_local) /= b_local }; const cntrl_uint_type result_cntrl { cntrl_uint_type(a_cntrl) /= b_cntrl }; const std::uint64_t result_local_lo = static_cast(result_local); const std::uint64_t result_local_hi = static_cast(result_local >> unsigned { UINT8_C(64) }); const std::uint64_t result_cntrl_lo = static_cast(result_cntrl); const std::uint64_t result_cntrl_hi = static_cast(result_cntrl >> unsigned { UINT8_C(64) }); // Verify that both the local (test) type as well as the // control type obtain the same numerical result. const bool result_is_ok { (result_local_lo == result_cntrl_lo) && (result_local_hi == result_cntrl_hi) }; if(!result_is_ok) { std::cout << "Error: lhs: " << a_local << ", rhs: " << b_local << ", result obtained: " << result_local << std::endl; } return result_is_ok; } // The fuzzing entry point. extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { constexpr std::size_t max_size { UINT8_C(32) }; constexpr std::size_t min_size { UINT8_C(17) }; bool result_is_ok { true }; if(((size >= min_size) && (size <= max_size)) && (data != nullptr)) { using local_data_array_type = std::array; local_data_array_type tmp_data { }; tmp_data.fill(UINT8_C(0)); static_cast(std::copy(data, data + size, tmp_data.begin())); const std::uint64_t a_lo64 { *reinterpret_cast(tmp_data.data() + std::size_t { UINT8_C(0) }) }; const std::uint64_t a_hi64 { *reinterpret_cast(tmp_data.data() + std::size_t { UINT8_C(8) }) }; const std::uint64_t b_lo64 { *reinterpret_cast(tmp_data.data() + std::size_t { UINT8_C(16) }) }; const std::uint64_t b_hi64 { *reinterpret_cast(tmp_data.data() + std::size_t { UINT8_C(24) }) }; // Import data into the uint values. using local_uint_type = ::boost::int128::uint128_t; #if defined(WIDE_INTEGER_NAMESPACE) using cntrl_uint_type = ::WIDE_INTEGER_NAMESPACE::math::wide_integer::uint128_t; #else using cntrl_uint_type = ::math::wide_integer::uint128_t; #endif cntrl_uint_type a_cntrl { a_hi64 }; a_cntrl <<= unsigned { UINT8_C(64) }; a_cntrl |= a_lo64; cntrl_uint_type b_cntrl { b_hi64 }; b_cntrl <<= unsigned { UINT8_C(64) }; b_cntrl |= b_lo64; local_uint_type a_local { a_hi64 }; a_local <<= unsigned { UINT8_C(64) }; a_local |= a_lo64; local_uint_type b_local { b_hi64 }; b_local <<= unsigned { UINT8_C(64) }; b_local |= b_lo64; if(a_local < b_local) { std::swap(a_local, b_local); std::swap(a_cntrl, b_cntrl); } if(b_local != 0U) { const bool result_op_is_ok { fuzzing::eval_op(a_cntrl, b_cntrl, a_local, b_local) }; if(!result_op_is_ok) { assert(result_op_is_ok); } result_is_ok = (result_op_is_ok && result_is_ok); } } return (result_is_ok ? 0 : -1); } ================================================ FILE: test/fuzzing/test_fuzzing_mul.cpp ================================================ /////////////////////////////////////////////////////////////////////////////// // Copyright Christopher Kormanyos 2024 - 2026. // Distributed under the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt // or copy at http://www.boost.org/LICENSE_1_0.txt) // // cd /mnt/c/Users/ckorm/Documents/Ks/PC_Software/NumericalPrograms/ExtendedNumberTypes/wide_integer // clang++ -std=c++20 -g -O2 -Wall -Wextra -fsanitize=fuzzer -I. -I/mnt/c/boost/boost_1_90_0 test/fuzzing/test_fuzzing_mul.cpp -o test_fuzzing_mul // ./test_fuzzing_mul -max_total_time=300 #include #include #include #include #include #include #include namespace fuzzing { using boost_uint_backend_type = boost::multiprecision::cpp_int_backend(UINT32_C(256)), static_cast(UINT32_C(256)), boost::multiprecision::unsigned_magnitude>; using boost_uint_type = boost::multiprecision::number; using local_uint_type = ::math::wide_integer::uint256_t; auto eval_op(const std::uint8_t* data, std::size_t size) -> bool; } auto fuzzing::eval_op(const std::uint8_t* data, std::size_t size) -> bool { const std::size_t max_size { static_cast ( std::numeric_limits::digits / 8 ) }; bool result_is_ok { true }; size = (std::min)(size, std::size_t { max_size * 2U }); if(size > std::size_t { UINT8_C(1) }) { local_uint_type a_local { 0U }; local_uint_type b_local { 0U }; boost_uint_type a_boost { 0U }; boost_uint_type b_boost { 0U }; // Import data into the uintwide_t values. import_bits ( a_local, data, data + std::size_t { size / 2U }, 8U ); import_bits ( b_local, data + std::size_t { size / 2U }, data + size, 8U ); // Import data into the boost values. import_bits ( a_boost, data, data + std::size_t { size / 2U }, 8U ); import_bits ( b_boost, data + std::size_t { size / 2U }, data + size, 8U ); local_uint_type result_local { a_local * b_local }; boost_uint_type result_boost { a_boost * b_boost }; std::vector result_data_local(max_size, UINT8_C(0)); std::vector result_data_boost(result_data_local.size(), UINT8_C(0)); export_bits(result_local, result_data_local.data(), 8U); export_bits(result_boost, result_data_boost.data(), 8U); // Verify that both uintwide_t as well as boost obtain the same result. const bool result_op_is_ok = std::equal ( result_data_local.cbegin(), result_data_local.cend(), result_data_boost.cbegin(), result_data_boost.cend() ); result_is_ok = (result_op_is_ok && result_is_ok); } // Assert the correct result. assert(result_is_ok); return result_is_ok; } // The fuzzing entry point. extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { const bool result_one_mul_is_ok { fuzzing::eval_op(data, size) }; return (result_one_mul_is_ok ? 0 : -1); } ================================================ FILE: test/fuzzing/test_fuzzing_powm.cpp ================================================ /////////////////////////////////////////////////////////////////////////////// // Copyright Christopher Kormanyos 2024 - 2026. // Distributed under the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt // or copy at http://www.boost.org/LICENSE_1_0.txt) // // cd /mnt/c/Users/ckorm/Documents/Ks/PC_Software/NumericalPrograms/ExtendedNumberTypes/wide_integer // clang++ -std=c++20 -g -O2 -Wall -Wextra -fsanitize=fuzzer -I. -I/mnt/c/boost/boost_1_90_0 test/fuzzing/test_fuzzing_powm.cpp -o test_fuzzing_powm // ./test_fuzzing_powm -max_total_time=300 #include #include #include #include #include #include #include namespace fuzzing { using boost_uint_backend_type = boost::multiprecision::cpp_int_backend(UINT32_C(256)), static_cast(UINT32_C(256)), boost::multiprecision::unsigned_magnitude>; using boost_uint_type = boost::multiprecision::number; using local_uint_type = ::math::wide_integer::uint256_t; auto eval_op(const std::uint8_t* data, std::size_t size) -> bool; } auto fuzzing::eval_op(const std::uint8_t* data, std::size_t size) -> bool { const std::size_t max_size { static_cast ( std::numeric_limits::digits / 8 ) }; bool result_is_ok { true }; if((size > std::size_t { UINT8_C(6) }) && (size <= std::size_t { max_size * 3U })) { local_uint_type b_local { 0U }; local_uint_type p_local { 0U }; local_uint_type m_local { 0U }; boost_uint_type b_boost { 0U }; boost_uint_type p_boost { 0U }; boost_uint_type m_boost { 0U }; // Import data into the uintwide_t values. import_bits ( b_local, data, data + std::size_t { size / 3U }, 8U ); import_bits ( p_local, data + std::size_t { size / 3U }, data + std::size_t { std::size_t { size * 2U } / 3U }, 8U ); import_bits ( m_local, data + std::size_t { std::size_t { size * 2U } / 3U }, data + size, 8U ); // Import data into the boost values. import_bits ( b_boost, data, data + std::size_t { size / 3U }, 8U ); import_bits ( p_boost, data + std::size_t { size / 3U }, data + std::size_t { std::size_t { size * 2U } / 3U }, 8U ); import_bits ( m_boost, data + std::size_t { std::size_t { size * 2U } / 3U }, data + size, 8U ); if(m_local != 0U) { local_uint_type result_local { powm(b_local, p_local, m_local) }; boost_uint_type result_boost { powm(b_boost, p_boost, m_boost) }; std::vector result_data_local(max_size, UINT8_C(0)); std::vector result_data_boost(result_data_local.size(), UINT8_C(0)); export_bits(result_local, result_data_local.data(), 8U); export_bits(result_boost, result_data_boost.data(), 8U); // Verify that both uintwide_t as well as boost obtain the same result. const bool result_op_is_ok = std::equal ( result_data_local.cbegin(), result_data_local.cend(), result_data_boost.cbegin(), result_data_boost.cend() ); result_is_ok = (result_op_is_ok && result_is_ok); } } // Assert the correct result. assert(result_is_ok); return result_is_ok; } // The fuzzing entry point. extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { const bool result_one_div_is_ok { fuzzing::eval_op(data, size) }; return (result_one_div_is_ok ? 0 : -1); } ================================================ FILE: test/fuzzing/test_fuzzing_prime.cpp ================================================ /////////////////////////////////////////////////////////////////////////////// // Copyright Christopher Kormanyos 2024 - 2026. // Distributed under the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt // or copy at http://www.boost.org/LICENSE_1_0.txt) // // cd /mnt/c/Users/ckorm/Documents/Ks/PC_Software/NumericalPrograms/ExtendedNumberTypes/wide_integer // clang++ -std=c++20 -g -O2 -Wall -Wextra -fsanitize=fuzzer -I. -I/mnt/c/boost/boost_1_90_0 test/fuzzing/test_fuzzing_prime.cpp -o test_fuzzing_prime // ./test_fuzzing_prime -max_total_time=300 -seed=$(($(date +%s%N) % 4294967295)) #include #include #include #include #include #include #include #include namespace fuzzing { using boost_uint_backend_type = boost::multiprecision::cpp_int_backend(UINT32_C(256)), static_cast(UINT32_C(256)), boost::multiprecision::unsigned_magnitude>; using boost_uint_type = boost::multiprecision::number; using local_uint_type = ::math::wide_integer::uint256_t; auto eval_op(const std::uint8_t* data, std::size_t size) -> bool; } auto fuzzing::eval_op(const std::uint8_t* data, std::size_t size) -> bool { const std::size_t max_size { static_cast ( std::numeric_limits::digits / 8 ) }; bool result_is_ok { true }; if(size <= max_size) { using random_engine_type = std::mt19937_64; using distribution_type = ::math::wide_integer::uniform_int_distribution; random_engine_type generator { util::util_pseudorandom_time_point_seed::value() }; static unsigned seed_prescaler { }; ++seed_prescaler; const auto seed_prescaler_mod1024 = static_cast<::std::uint32_t>(seed_prescaler % static_cast<::std::uint32_t>(UINT16_C(1024))); if(seed_prescaler_mod1024 == static_cast<::std::uint32_t>(UINT8_C(0))) { using random_engine_result_type = typename random_engine_type::result_type; generator.seed(util::util_pseudorandom_time_point_seed::value()); } local_uint_type p0 { 0U }; boost_uint_type pb { 0U }; // Import data into the uintwide_t prime candidate. import_bits ( p0, data, data + size, 8U ); // Import data into the boost prime candidate. import_bits ( pb, data, data + size, 8U ); distribution_type dist2 { local_uint_type { 2U }, p0 - 1U }; // Ensure that both uintwide_t as well as boost obtain // the same prime (or non-prime) result. const bool miller_rabin_is_prime_local { miller_rabin(p0, 25U, dist2, generator) }; const bool miller_rabin_is_prime_boost { boost::multiprecision::miller_rabin_test(pb, 25U, generator) }; const bool result_op_is_ok { (miller_rabin_is_prime_local == miller_rabin_is_prime_boost) }; result_is_ok = (result_op_is_ok && result_is_ok); } // Assert the correct result. assert(result_is_ok); return result_is_ok; } // The fuzzing entry point. extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { const bool result_one_prime_is_ok { fuzzing::eval_op(data, size) }; return (result_one_prime_is_ok ? 0 : -1); } ================================================ FILE: test/fuzzing/test_fuzzing_sdiv.cpp ================================================ /////////////////////////////////////////////////////////////////////////////// // Copyright Christopher Kormanyos 2024 - 2026. // Distributed under the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt // or copy at http://www.boost.org/LICENSE_1_0.txt) // // cd /mnt/c/Users/ckorm/Documents/Ks/PC_Software/NumericalPrograms/ExtendedNumberTypes/wide_integer // clang++ -std=c++20 -g -O2 -Wall -Wextra -fsanitize=fuzzer -I. -I/mnt/c/boost/boost_1_90_0 test/fuzzing/test_fuzzing_sdiv.cpp -o test_fuzzing_sdiv // ./test_fuzzing_sdiv -max_total_time=300 #include #include #include #include #include #include #include #include #include namespace fuzzing { auto pseudo_random_sign_bit() -> int { static unsigned seed_prescaler { }; static std::mt19937 engine { }; if((seed_prescaler++ % 0x10000U) == 0U) { std::random_device rd { }; engine.seed(rd()); } // Create a uniform distribution for the bit position (0 to 1). static std::uniform_int_distribution bit_dist(0, 1); // Generate a pseudo-random sign bit. return bit_dist(engine); } using boost_uint_backend_type = boost::multiprecision::cpp_int_backend(UINT32_C(256)), static_cast(UINT32_C(256)), boost::multiprecision::unsigned_magnitude>; using boost_uint_type = boost::multiprecision::number; using local_uint_type = ::math::wide_integer::uint256_t; using boost_sint_backend_type = boost::multiprecision::cpp_int_backend(UINT32_C(256)), static_cast(UINT32_C(256)), boost::multiprecision::signed_magnitude>; using boost_sint_type = boost::multiprecision::number; using local_sint_type = ::math::wide_integer::int256_t; auto eval_op(const std::uint8_t* data, std::size_t size) -> bool; } auto fuzzing::eval_op(const std::uint8_t* data, std::size_t size) -> bool { const std::size_t max_size { static_cast ( std::numeric_limits::digits / 8 ) }; bool result_is_ok { true }; size = (std::min)(size, std::size_t { max_size * 2U }); if(size > std::size_t { UINT8_C(1) }) { local_uint_type a_local { 0U }; local_uint_type b_local { 0U }; // Import data into the uintwide_t values. import_bits ( a_local, data, data + std::size_t { size / 2U }, 8U ); import_bits ( b_local, data + std::size_t { size / 2U }, data + size, 8U ); if(a_local + 256U < b_local) { std::swap(a_local, b_local); } if(b_local != 0U) { local_sint_type a_signed_local { a_local }; local_sint_type b_signed_local { b_local }; const int sign_mixer { (pseudo_random_sign_bit() << 1U) | pseudo_random_sign_bit() }; if (sign_mixer == 0) { } else if(sign_mixer == 1) { a_signed_local = -a_signed_local; } else if(sign_mixer == 2) { b_signed_local = -b_signed_local; } else { a_signed_local = -a_signed_local; b_signed_local = -b_signed_local; } std::stringstream strm_a_local { }; std::stringstream strm_b_local { }; strm_a_local << a_signed_local; strm_b_local << b_signed_local; boost_sint_type a_signed_boost { strm_a_local.str() }; boost_sint_type b_signed_boost { strm_b_local.str() }; local_sint_type result_signed_local { a_signed_local / b_signed_local }; boost_sint_type result_signed_boost { a_signed_boost / b_signed_boost }; std::vector result_signed_data_local(max_size, UINT8_C(0)); std::vector result_signed_data_boost(result_signed_data_local.size(), UINT8_C(0)); export_bits(result_signed_local, result_signed_data_local.data(), 8U); export_bits(result_signed_boost, result_signed_data_boost.data(), 8U); // Verify that both uintwide_t as well as boost obtain the same result. const bool result_op_is_ok = std::equal ( result_signed_data_local.cbegin(), result_signed_data_local.cend(), result_signed_data_boost.cbegin(), result_signed_data_boost.cend() ); result_is_ok = (result_op_is_ok && result_is_ok); } } // Assert the correct result. assert(result_is_ok); return result_is_ok; } // The fuzzing entry point. extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { const bool result_one_div_is_ok { fuzzing::eval_op(data, size) }; return (result_one_div_is_ok ? 0 : -1); } ================================================ FILE: test/fuzzing/test_fuzzing_sqrt.cpp ================================================ /////////////////////////////////////////////////////////////////////////////// // Copyright Christopher Kormanyos 2024 - 2026. // Distributed under the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt // or copy at http://www.boost.org/LICENSE_1_0.txt) // // cd /mnt/c/Users/ckorm/Documents/Ks/PC_Software/NumericalPrograms/ExtendedNumberTypes/wide_integer // clang++ -std=c++20 -g -O2 -Wall -Wextra -fsanitize=fuzzer -I. -I/mnt/c/boost/boost_1_90_0 test/fuzzing/test_fuzzing_sqrt.cpp -o test_fuzzing_sqrt // ./test_fuzzing_sqrt -max_total_time=300 #include #include #include #include #include #include #include #include #include namespace fuzzing { using boost_uint_backend_type = boost::multiprecision::cpp_int_backend(UINT32_C(256)), static_cast(UINT32_C(256)), boost::multiprecision::unsigned_magnitude>; using boost_uint_type = boost::multiprecision::number; using local_uint_type = ::math::wide_integer::uint256_t; auto eval_op(const std::uint8_t* data, std::size_t size) -> bool; } auto fuzzing::eval_op(const std::uint8_t* data, std::size_t size) -> bool { const std::size_t max_size { static_cast ( std::numeric_limits::digits / 8 ) }; bool result_is_ok { true }; if(size <= max_size) { local_uint_type a_local { 0U }; // Import data into the uintwide_t values. import_bits ( a_local, data, data + size, 8U ); std::stringstream strm_a_local { }; strm_a_local << a_local; boost_uint_type a_boost { strm_a_local.str() }; local_uint_type result_local { sqrt(a_local) }; boost_uint_type result_boost { sqrt(a_boost) }; std::vector result_data_local(max_size, UINT8_C(0)); std::vector result_data_boost(max_size, UINT8_C(0)); export_bits(result_local, result_data_local.data(), 8U); export_bits(result_boost, result_data_boost.data(), 8U); // Verify that both uintwide_t as well as boost obtain the same result. const bool result_op_is_ok = std::equal ( result_data_local.cbegin(), result_data_local.cend(), result_data_boost.cbegin(), result_data_boost.cend() ); result_is_ok = (result_op_is_ok && result_is_ok); } // Assert the correct result. assert(result_is_ok); return result_is_ok; } // The fuzzing entry point. extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { const bool result_one_div_is_ok { fuzzing::eval_op(data, size) }; return (result_one_div_is_ok ? 0 : -1); } ================================================ FILE: test/fuzzing/test_fuzzing_sub.cpp ================================================ /////////////////////////////////////////////////////////////////////////////// // Copyright Christopher Kormanyos 2024 - 2026. // Distributed under the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt // or copy at http://www.boost.org/LICENSE_1_0.txt) // // cd /mnt/c/Users/ckorm/Documents/Ks/PC_Software/NumericalPrograms/ExtendedNumberTypes/wide_integer // clang++ -std=c++20 -g -O2 -Wall -Wextra -fsanitize=fuzzer -I. -I/mnt/c/boost/boost_1_90_0 test/fuzzing/test_fuzzing_sub.cpp -o test_fuzzing_sub // ./test_fuzzing_sub -max_total_time=300 #include #include #include #include #include #include #include namespace fuzzing { using boost_uint_backend_type = boost::multiprecision::cpp_int_backend(UINT32_C(256)), static_cast(UINT32_C(256)), boost::multiprecision::unsigned_magnitude>; using boost_uint_type = boost::multiprecision::number; using local_uint_type = ::math::wide_integer::uint256_t; auto eval_op(const std::uint8_t* data, std::size_t size) -> bool; } auto fuzzing::eval_op(const std::uint8_t* data, std::size_t size) -> bool { const std::size_t max_size { static_cast ( std::numeric_limits::digits / 8 ) }; bool result_is_ok { true }; size = (std::min)(size, std::size_t { max_size * 2U }); if(size > std::size_t { UINT8_C(1) }) { local_uint_type a_local { 0U }; local_uint_type b_local { 0U }; boost_uint_type a_boost { 0U }; boost_uint_type b_boost { 0U }; // Import data into the uintwide_t values. import_bits ( a_local, data, data + std::size_t { size / 2U }, 8U ); import_bits ( b_local, data + std::size_t { size / 2U }, data + size, 8U ); // Import data into the boost values. import_bits ( a_boost, data, data + std::size_t { size / 2U }, 8U ); import_bits ( b_boost, data + std::size_t { size / 2U }, data + size, 8U ); local_uint_type result_local { a_local - b_local }; boost_uint_type result_boost { a_boost - b_boost }; std::vector result_data_local(max_size, UINT8_C(0)); std::vector result_data_boost(result_data_local.size(), UINT8_C(0)); export_bits(result_local, result_data_local.data(), 8U); export_bits(result_boost, result_data_boost.data(), 8U); // Verify that both uintwide_t as well as boost obtain the same result. const bool result_op_is_ok = std::equal ( result_data_local.cbegin(), result_data_local.cend(), result_data_boost.cbegin(), result_data_boost.cend() ); result_is_ok = (result_op_is_ok && result_is_ok); } // Assert the correct result. assert(result_is_ok); return result_is_ok; } // The fuzzing entry point. extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { const bool result_one_sub_is_ok { fuzzing::eval_op(data, size) }; return (result_one_sub_is_ok ? 0 : -1); } ================================================ FILE: test/parallel_for.h ================================================ /////////////////////////////////////////////////////////////////////////////// // Copyright Christopher Kormanyos 2017 - 2025. // Distributed under the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt // or copy at http://www.boost.org/LICENSE_1_0.txt) // #ifndef PARALLEL_FOR_2017_12_18_H // NOLINT(llvm-header-guard) #define PARALLEL_FOR_2017_12_18_H #include #include #include namespace my_concurrency { template auto parallel_for(index_type start, index_type end, callable_function_type parallel_function) -> void { // Estimate the number of threads available. const auto number_of_threads_hint = static_cast ( std::thread::hardware_concurrency() ); const auto number_of_threads = // NOLINT(altera-id-dependent-backward-branch) static_cast ( (number_of_threads_hint == static_cast(UINT8_C(0))) ? static_cast(UINT8_C(4)) : number_of_threads_hint // NOLINT(altera-id-dependent-backward-branch) ); // Set the size of a slice for the range functions. const auto n = static_cast ( static_cast(end - start) + static_cast(1) ); const auto slice = (std::max) ( static_cast(std::round(static_cast(n) / static_cast(number_of_threads))), static_cast(1) ); // Inner loop. const auto launch_range = [¶llel_function](index_type index_lo, index_type index_hi) { for(auto i = index_lo; i < index_hi; ++i) // NOLINT(altera-id-dependent-backward-branch) { parallel_function(i); } }; // Create the thread pool and launch the jobs. std::vector pool { }; pool.reserve(number_of_threads); auto i1 = start; auto i2 = (std::min)(static_cast(start + slice), end); for(auto i = static_cast(0U); ((static_cast(i + 1) < static_cast(number_of_threads)) && (i1 < end)); ++i) // NOLINT(altera-id-dependent-backward-branch) { pool.emplace_back(launch_range, i1, i2); i1 = i2; i2 = (std::min)(static_cast(i2 + slice), end); } if(i1 < end) { pool.emplace_back(launch_range, i1, end); } // Wait for the jobs to finish. for(auto& thread_in_pool : pool) { if(thread_in_pool.joinable()) { thread_in_pool.join(); } } } // Provide a serial version for easy comparison. template auto sequential_for(index_type start, index_type end, callable_function_type sequential_function) -> void { for(index_type i = start; i < end; ++i) { sequential_function(i); } } } // namespace my_concurrency #endif // PARALLEL_FOR_2017_12_18_H ================================================ FILE: test/stopwatch.h ================================================ /////////////////////////////////////////////////////////////////////////////// // Copyright Christopher Kormanyos 2013 - 2025. // Distributed under the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt // or copy at http://www.boost.org/LICENSE_1_0.txt) // #ifndef STOPWATCH_2024_03_28_H // NOLINT(llvm-header-guard) #define STOPWATCH_2024_03_28_H #include #include #if defined(_MSC_VER) && !defined(__GNUC__) #define STOPWATCH_NODISCARD #else #if (defined(__cplusplus) && (__cplusplus >= 201703L)) #define STOPWATCH_NODISCARD [[nodiscard]] // NOLINT(cppcoreguidelines-macro-usage) #else #define STOPWATCH_NODISCARD #endif #endif // See also: https://godbolt.org/z/37a4n9f4Y namespace concurrency { struct stopwatch { public: using time_point_type = std::uintmax_t; auto reset() -> void { m_start = now(); } template static auto elapsed_time(const stopwatch& my_stopwatch) noexcept -> RepresentationRequestedTimeType { using local_time_type = RepresentationRequestedTimeType; return local_time_type { static_cast(my_stopwatch.elapsed()) / local_time_type { UINTMAX_C(1000000000) } }; } private: time_point_type m_start { now() }; // NOLINT(readability-identifier-naming) STOPWATCH_NODISCARD static auto now() -> time_point_type { #if defined(__CYGWIN__) return static_cast(std::clock()); #else timespec ts { }; const int ntsp { timespec_get(&ts, TIME_UTC) }; static_cast(ntsp); return static_cast ( static_cast(static_cast(ts.tv_sec) * UINTMAX_C(1000000000)) + static_cast(ts.tv_nsec) ); #endif } STOPWATCH_NODISCARD auto elapsed() const -> time_point_type { const time_point_type stop { now() }; #if defined(__CYGWIN__) const time_point_type elapsed_ns { static_cast ( static_cast(static_cast(stop - m_start) * UINTMAX_C(1000000000)) / static_cast(CLOCKS_PER_SEC) ) }; #else const time_point_type elapsed_ns { static_cast ( stop - m_start ) }; #endif return elapsed_ns; } }; } // namespace concurrency #endif // STOPWATCH_2024_03_28_H ================================================ FILE: test/test.cpp ================================================ /////////////////////////////////////////////////////////////////// // Copyright Christopher Kormanyos 2018 - 2026. // // Distributed under the Boost Software License, // // Version 1.0. (See accompanying file LICENSE_1_0.txt // // or copy at http://www.boost.org/LICENSE_1_0.txt) // /////////////////////////////////////////////////////////////////// // On Windows subsystem for LINUX // cd /mnt/c/Users/ckorm/Documents/Ks/PC_Software/NumericalPrograms/ExtendedNumberTypes/wide_integer // When using local Boost-develop branch, use specific include paths. // -I/mnt/c/boost/modular_boost/boost/libs/config/include -I/mnt/c/boost/modular_boost/boost/libs/multiprecision/include // When using -std=c++14/20 and g++ // g++ -finline-functions -march=native -mtune=native -O3 -Werror -Wall -Wextra -Wpedantic -Wconversion -Wsign-conversion -Wshadow -Wundef -Wunused-parameter -Wuninitialized -Wunreachable-code -Winit-self -Wmissing-declarations -Wzero-as-null-pointer-constant -std=c++14 -DWIDE_INTEGER_HAS_LIMB_TYPE_UINT64 -DWIDE_INTEGER_HAS_MUL_8_BY_8_UNROLL -I. -I/mnt/c/boost/boost_1_90_0 -pthread -lpthread test/test.cpp test/test_uintwide_t_boost_backend.cpp test/test_uintwide_t_edge_cases.cpp test/test_uintwide_t_examples.cpp test/test_uintwide_t_float_convert.cpp test/test_uintwide_t_int_convert.cpp test/test_uintwide_t_n_base.cpp test/test_uintwide_t_n_binary_ops_base.cpp examples/example000a_builtin_convert.cpp test/test_uintwide_t_spot_values.cpp examples/example000_numeric_limits.cpp examples/example001_mul_div.cpp examples/example001a_div_mod.cpp examples/example002_shl_shr.cpp examples/example003_sqrt.cpp examples/example003a_cbrt.cpp examples/example004_rootk_pow.cpp examples/example005_powm.cpp examples/example005a_pow_factors_of_p99.cpp examples/example006_gcd.cpp examples/example007_random_generator.cpp examples/example008_miller_rabin_prime.cpp examples/example008a_miller_rabin_prime.cpp examples/example008b_solovay_strassen_prime.cpp examples/example009_timed_mul.cpp examples/example009a_timed_mul_4_by_4.cpp examples/example009b_timed_mul_8_by_8.cpp examples/example010_uint48_t.cpp examples/example011_uint24_t.cpp examples/example012_rsa_crypto.cpp examples/example013_ecdsa_sign_verify.cpp examples/example014_pi_spigot_wide.cpp -o wide_integer.exe // g++ -finline-functions -march=native -mtune=native -O3 -Werror -Wall -Wextra -Wpedantic -Wconversion -Wsign-conversion -Wshadow -Wundef -Wunused-parameter -Wuninitialized -Wunreachable-code -Winit-self -Wmissing-declarations -Wzero-as-null-pointer-constant -std=c++20 -DWIDE_INTEGER_HAS_LIMB_TYPE_UINT64 -DWIDE_INTEGER_HAS_MUL_8_BY_8_UNROLL -I. -I/mnt/c/boost/boost_1_90_0 -pthread -lpthread test/test.cpp test/test_uintwide_t_boost_backend.cpp test/test_uintwide_t_edge_cases.cpp test/test_uintwide_t_examples.cpp test/test_uintwide_t_float_convert.cpp test/test_uintwide_t_int_convert.cpp test/test_uintwide_t_n_base.cpp test/test_uintwide_t_n_binary_ops_base.cpp examples/example000a_builtin_convert.cpp test/test_uintwide_t_spot_values.cpp examples/example000_numeric_limits.cpp examples/example001_mul_div.cpp examples/example001a_div_mod.cpp examples/example002_shl_shr.cpp examples/example003_sqrt.cpp examples/example003a_cbrt.cpp examples/example004_rootk_pow.cpp examples/example005_powm.cpp examples/example005a_pow_factors_of_p99.cpp examples/example006_gcd.cpp examples/example007_random_generator.cpp examples/example008_miller_rabin_prime.cpp examples/example008a_miller_rabin_prime.cpp examples/example008b_solovay_strassen_prime.cpp examples/example009_timed_mul.cpp examples/example009a_timed_mul_4_by_4.cpp examples/example009b_timed_mul_8_by_8.cpp examples/example010_uint48_t.cpp examples/example011_uint24_t.cpp examples/example012_rsa_crypto.cpp examples/example013_ecdsa_sign_verify.cpp examples/example014_pi_spigot_wide.cpp -o wide_integer.exe // cd /mnt/c/Users/ckorm/Documents/Ks/PC_Software/NumericalPrograms/ExtendedNumberTypes/wide_integer // cd .tidy/make // make prepare -f make_tidy_01_generic.gmk MY_BOOST_ROOT=/mnt/c/boost/boost_1_90_0 // make tidy -f make_tidy_01_generic.gmk --jobs=8 MY_BOOST_ROOT=/mnt/c/boost/boost_1_90_0 // cd /mnt/c/Users/ckorm/Documents/Ks/PC_Software/NumericalPrograms/ExtendedNumberTypes/wide_integer // cd .gcov/make // make prepare -f make_gcov_01_generic.gmk MY_ALL_COV=0 MY_BOOST_ROOT=/mnt/c/boost/boost_1_90_0 MY_CC=g++ // make gcov -f make_gcov_01_generic.gmk --jobs=8 MY_ALL_COV=0 MY_BOOST_ROOT=/mnt/c/boost/boost_1_90_0 MY_CC=g++ // cd /mnt/c/Users/ckorm/Documents/Ks/PC_Software/NumericalPrograms/ExtendedNumberTypes/wide_integer // PATH=/home/chris/coverity/cov-analysis-linux64-2023.12.2/bin:$PATH // cov-build --dir cov-int g++ -finline-functions -march=native -mtune=native -O3 -Werror -Wall -Wextra -Wpedantic -Wconversion -Wsign-conversion -Wshadow -Wundef -Wunused-parameter -Wuninitialized -Wunreachable-code -Winit-self -Wzero-as-null-pointer-constant -std=c++14 -DWIDE_INTEGER_HAS_LIMB_TYPE_UINT64 -DWIDE_INTEGER_HAS_MUL_8_BY_8_UNROLL -I. -I/mnt/c/boost/boost_1_90_0 -pthread -lpthread test/test.cpp test/test_uintwide_t_boost_backend.cpp test/test_uintwide_t_edge_cases.cpp test/test_uintwide_t_examples.cpp test/test_uintwide_t_float_convert.cpp test/test_uintwide_t_int_convert.cpp test/test_uintwide_t_n_base.cpp test/test_uintwide_t_n_binary_ops_base.cpp examples/example000a_builtin_convert.cpp test/test_uintwide_t_spot_values.cpp examples/example000_numeric_limits.cpp examples/example001_mul_div.cpp examples/example001a_div_mod.cpp examples/example002_shl_shr.cpp examples/example003_sqrt.cpp examples/example003a_cbrt.cpp examples/example004_rootk_pow.cpp examples/example005_powm.cpp examples/example005a_pow_factors_of_p99.cpp examples/example006_gcd.cpp examples/example007_random_generator.cpp examples/example008_miller_rabin_prime.cpp examples/example008a_miller_rabin_prime.cpp examples/example009_timed_mul.cpp examples/example009a_timed_mul_4_by_4.cpp examples/example009b_timed_mul_8_by_8.cpp examples/example010_uint48_t.cpp examples/example011_uint24_t.cpp examples/example012_rsa_crypto.cpp examples/example013_ecdsa_sign_verify.cpp examples/example014_pi_spigot_wide.cpp -o wide_integer.exe // tar caf wide-integer.bz2 cov-int #include #include #include #include #include #if !defined(BOOST_VERSION) #error BOOST_VERSION is not defined. Ensure that is properly included. #endif #if ((BOOST_VERSION >= 107900) && !defined(BOOST_MP_STANDALONE)) #define BOOST_MP_STANDALONE #endif #if ((BOOST_VERSION >= 108000) && !defined(BOOST_NO_EXCEPTIONS)) #define BOOST_NO_EXCEPTIONS #endif #if (((BOOST_VERSION == 108000) || (BOOST_VERSION == 108100)) && defined(BOOST_NO_EXCEPTIONS)) #if defined(__clang__) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wsometimes-uninitialized" #endif #if defined(_MSC_VER) #pragma warning(push) #pragma warning(disable : 4701) #endif #endif #if (BOOST_VERSION < 107900) #if defined(__GNUC__) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wconversion" #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wsign-conversion" #endif #endif #if (defined(__GNUC__) && !defined(__clang__) && (__GNUC__ >= 12)) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wrestrict" #endif #if (BOOST_VERSION < 107900) #include #endif #include #include #include #include #include #if defined(__clang__) #if defined __has_feature && __has_feature(thread_sanitizer) #define UINTWIDE_T_REDUCE_TEST_DEPTH #endif #elif defined(__GNUC__) #if defined(__SANITIZE_THREAD__) || defined(WIDE_INTEGER_HAS_COVERAGE) #define UINTWIDE_T_REDUCE_TEST_DEPTH #endif #elif defined(_MSC_VER) #if defined(_DEBUG) #define UINTWIDE_T_REDUCE_TEST_DEPTH #endif #endif namespace local { #if !defined(UINTWIDE_T_REDUCE_TEST_DEPTH) constexpr auto test_uintwide_t_n_binary_ops_rounds = static_cast(4U); // NOLINT(cppcoreguidelines-avoid-magic-numbers,readability-magic-numbers) #else constexpr auto test_uintwide_t_n_binary_ops_rounds = static_cast(1U); // NOLINT(cppcoreguidelines-avoid-magic-numbers,readability-magic-numbers) #endif #if !defined(UINTWIDE_T_REDUCE_TEST_DEPTH) constexpr std::size_t test_uintwide_t_n_binary_ops_4_by_4_cases = std::uint32_t(1UL << 15U); // NOLINT(cppcoreguidelines-avoid-magic-numbers,readability-magic-numbers) #else constexpr std::size_t test_uintwide_t_n_binary_ops_4_by_4_cases = std::uint32_t(1UL << 9U); // NOLINT(cppcoreguidelines-avoid-magic-numbers,readability-magic-numbers) #endif auto test_uintwide_t_small_bits() -> bool; auto test_uintwide_t_boost_backend() -> bool; auto test_uintwide_t_examples() -> bool; auto test_uintwide_t_edge_cases() -> bool; auto test_uintwide_t_float_convert() -> bool; auto test_uintwide_t_int_convert() -> bool; auto test_uintwide_t_spot_values() -> bool; auto test_uintwide_t_0000024() -> bool; auto test_uintwide_t_0000048() -> bool; auto test_uintwide_t_0000064() -> bool; auto test_uintwide_t_0000064_signed() -> bool; auto test_uintwide_t_0000096() -> bool; auto test_uintwide_t_0000128() -> bool; auto test_uintwide_t_0000256() -> bool; #if defined(WIDE_INTEGER_HAS_LIMB_TYPE_UINT64) auto test_uintwide_t_0000256_limb_type_uint64_t() -> bool; #endif auto test_uintwide_t_0000512() -> bool; auto test_uintwide_t_0000512_signed() -> bool; auto test_uintwide_t_0001024() -> bool; auto test_uintwide_t_0002048() -> bool; auto test_uintwide_t_0008192() -> bool; #if defined(WIDE_INTEGER_HAS_LIMB_TYPE_UINT64) auto test_uintwide_t_0008192_limb_type_uint64_t() -> bool; #endif auto test_uintwide_t_0012288() -> bool; auto test_uintwide_t_0032768() -> bool; auto test_uintwide_t_0065536_alloc() -> bool; auto test_uintwide_t_0008192_by_0012288() -> bool; auto test_uintwide_t_0012288_by_0008192() -> bool; auto test_uintwide_t_0000032_by_0000032_4_by_4() -> bool; auto test_uintwide_t_0000064_by_0000064_4_by_4() -> bool; auto run() -> bool; auto test_uintwide_t_small_bits() -> bool { std::cout << "running: test_uintwide_t_small_bits" << std::endl; bool result_is_ok = true; { #if defined(WIDE_INTEGER_NAMESPACE) using local_uint16_t = WIDE_INTEGER_NAMESPACE::math::wide_integer::uintwide_t(UINT32_C(16)), std::uint8_t>; #else using local_uint16_t = ::math::wide_integer::uintwide_t(UINT32_C(16)), std::uint8_t>; #endif local_uint16_t a = UINT16_C(0x5522); // NOLINT(cppcoreguidelines-avoid-magic-numbers,readability-magic-numbers) local_uint16_t b = UINT16_C(0xFFEE); // NOLINT(cppcoreguidelines-avoid-magic-numbers,readability-magic-numbers) local_uint16_t c = a * b; result_is_ok = ((c == UINT32_C(0x039C)) && result_is_ok); // NOLINT(cppcoreguidelines-avoid-magic-numbers,readability-magic-numbers) } { #if defined(WIDE_INTEGER_NAMESPACE) using local_uint24_t = WIDE_INTEGER_NAMESPACE::math::wide_integer::uintwide_t(UINT32_C(24)), std::uint8_t>; #else using local_uint24_t = ::math::wide_integer::uintwide_t(UINT32_C(24)), std::uint8_t>; #endif local_uint24_t a = UINT32_C(0x11FF5522); // NOLINT(cppcoreguidelines-avoid-magic-numbers,readability-magic-numbers) local_uint24_t b = UINT32_C(0xABCDFFEE); // NOLINT(cppcoreguidelines-avoid-magic-numbers,readability-magic-numbers) local_uint24_t c = a * b; result_is_ok = ((c == UINT32_C(0x0068039C)) && result_is_ok); // NOLINT(cppcoreguidelines-avoid-magic-numbers,readability-magic-numbers) } { #if defined(WIDE_INTEGER_NAMESPACE) using local_uint32_t = WIDE_INTEGER_NAMESPACE::math::wide_integer::uintwide_t(UINT32_C(32)), std::uint16_t>; #else using local_uint32_t = ::math::wide_integer::uintwide_t(UINT32_C(32)), std::uint16_t>; #endif local_uint32_t a = UINT32_C(0x11FF5522); // NOLINT(cppcoreguidelines-avoid-magic-numbers,readability-magic-numbers) local_uint32_t b = UINT32_C(0xABCDFFEE); // NOLINT(cppcoreguidelines-avoid-magic-numbers,readability-magic-numbers) local_uint32_t c = a * b; result_is_ok = ((c == UINT32_C(0xF368039C)) && result_is_ok); // NOLINT(cppcoreguidelines-avoid-magic-numbers,readability-magic-numbers) } return result_is_ok; } auto test_uintwide_t_boost_backend() -> bool { std::cout << "running: test_uintwide_t_boost_backend" << std::endl; #if defined(WIDE_INTEGER_NAMESPACE) const bool result_test_uintwide_t_boost_backend_is_ok = WIDE_INTEGER_NAMESPACE::math::wide_integer::test_uintwide_t_boost_backend(); #else const bool result_test_uintwide_t_boost_backend_is_ok = ::math::wide_integer::test_uintwide_t_boost_backend(); #endif return result_test_uintwide_t_boost_backend_is_ok; } auto test_uintwide_t_examples() -> bool { std::cout << "running: test_uintwide_t_examples" << std::endl; #if defined(WIDE_INTEGER_NAMESPACE) const bool result_test_uintwide_t_examples_is_ok = WIDE_INTEGER_NAMESPACE::math::wide_integer::test_uintwide_t_examples(); #else const bool result_test_uintwide_t_examples_is_ok = ::math::wide_integer::test_uintwide_t_examples(); #endif return result_test_uintwide_t_examples_is_ok; } auto test_uintwide_t_edge_cases() -> bool { std::cout << "running: test_uintwide_t_edge_cases" << std::endl; #if defined(WIDE_INTEGER_NAMESPACE) const bool result_test_uintwide_t_edge_cases_is_ok = WIDE_INTEGER_NAMESPACE::math::wide_integer::test_uintwide_t_edge_cases(); #else const bool result_test_uintwide_t_edge_cases_is_ok = ::math::wide_integer::test_uintwide_t_edge_cases(); #endif return result_test_uintwide_t_edge_cases_is_ok; } auto test_uintwide_t_float_convert() -> bool { std::cout << "running: test_uintwide_t_float_convert" << std::endl; #if defined(WIDE_INTEGER_NAMESPACE) const bool result_test_uintwide_t_float_convert_is_ok = WIDE_INTEGER_NAMESPACE::math::wide_integer::test_uintwide_t_float_convert(); #else const bool result_test_uintwide_t_float_convert_is_ok = ::math::wide_integer::test_uintwide_t_float_convert(); #endif return result_test_uintwide_t_float_convert_is_ok; } auto test_uintwide_t_int_convert() -> bool { std::cout << "running: test_uintwide_t_int_convert" << std::endl; #if defined(WIDE_INTEGER_NAMESPACE) const bool result_test_uintwide_t_int_convert_is_ok = WIDE_INTEGER_NAMESPACE::math::wide_integer::test_uintwide_t_int_convert(); #else const bool result_test_uintwide_t_int_convert_is_ok = ::math::wide_integer::test_uintwide_t_int_convert(); #endif return result_test_uintwide_t_int_convert_is_ok; } auto test_uintwide_t_spot_values() -> bool { std::cout << "running: test_uintwide_t_spot_values" << std::endl; #if defined(WIDE_INTEGER_NAMESPACE) const bool result_test_uintwide_t_spot_values_is_ok = WIDE_INTEGER_NAMESPACE::math::wide_integer::test_uintwide_t_spot_values(); #else const bool result_test_uintwide_t_spot_values_is_ok = ::math::wide_integer::test_uintwide_t_spot_values(); #endif return result_test_uintwide_t_spot_values_is_ok; } auto test_uintwide_t_0000024() -> bool { #if !defined(UINTWIDE_T_REDUCE_TEST_DEPTH) constexpr auto count = static_cast(1UL << 13U); #else constexpr auto count = static_cast(1UL << 10U); #endif std::cout << "running: test_uintwide_t_0000024" << std::endl; test_uintwide_t_n_binary_ops_template<24U, std::uint8_t> test_uintwide_t_n_binary_ops_template_instance(count); // NOLINT(cppcoreguidelines-avoid-magic-numbers,readability-magic-numbers) const auto result_is_ok = test_uintwide_t_n_binary_ops_template_instance.do_test(test_uintwide_t_n_binary_ops_rounds); return result_is_ok; } auto test_uintwide_t_0000048() -> bool { #if !defined(UINTWIDE_T_REDUCE_TEST_DEPTH) constexpr auto count = static_cast(1UL << 13U); #else constexpr auto count = static_cast(1UL << 10U); #endif std::cout << "running: test_uintwide_t_0000048" << std::endl; test_uintwide_t_n_binary_ops_template<48U, std::uint16_t> test_uintwide_t_n_binary_ops_template_instance(count); // NOLINT(cppcoreguidelines-avoid-magic-numbers,readability-magic-numbers) const auto result_is_ok = test_uintwide_t_n_binary_ops_template_instance.do_test(test_uintwide_t_n_binary_ops_rounds); return result_is_ok; } auto test_uintwide_t_0000064() -> bool { #if !defined(UINTWIDE_T_REDUCE_TEST_DEPTH) constexpr auto count = static_cast(1UL << 13U); #else constexpr auto count = static_cast(1UL << 10U); #endif std::cout << "running: test_uintwide_t_0000064" << std::endl; test_uintwide_t_n_binary_ops_template<64U, std::uint32_t> test_uintwide_t_n_binary_ops_template_instance(count); // NOLINT(cppcoreguidelines-avoid-magic-numbers,readability-magic-numbers) const auto result_is_ok = test_uintwide_t_n_binary_ops_template_instance.do_test(test_uintwide_t_n_binary_ops_rounds); return result_is_ok; } auto test_uintwide_t_0000064_signed() -> bool { #if !defined(UINTWIDE_T_REDUCE_TEST_DEPTH) constexpr auto count = static_cast(1UL << 13U); #else constexpr auto count = static_cast(1UL << 10U); #endif std::cout << "running: test_uintwide_t_0000064_signed" << std::endl; test_uintwide_t_n_binary_ops_template_signed<64U, std::uint16_t> test_uintwide_t_n_binary_ops_template_instance(count); // NOLINT(cppcoreguidelines-avoid-magic-numbers,readability-magic-numbers) const auto result_is_ok = test_uintwide_t_n_binary_ops_template_instance.do_test(test_uintwide_t_n_binary_ops_rounds); return result_is_ok; } auto test_uintwide_t_0000096() -> bool { #if !defined(UINTWIDE_T_REDUCE_TEST_DEPTH) constexpr auto count = static_cast(1UL << 13U); #else constexpr auto count = static_cast(1UL << 10U); #endif std::cout << "running: test_uintwide_t_0000096" << std::endl; test_uintwide_t_n_binary_ops_template<96U, std::uint16_t> test_uintwide_t_n_binary_ops_template_instance(count); // NOLINT(cppcoreguidelines-avoid-magic-numbers,readability-magic-numbers) const auto result_is_ok = test_uintwide_t_n_binary_ops_template_instance.do_test(test_uintwide_t_n_binary_ops_rounds); return result_is_ok; } auto test_uintwide_t_0000128() -> bool { #if !defined(UINTWIDE_T_REDUCE_TEST_DEPTH) constexpr auto count = static_cast(1UL << 13U); #else constexpr auto count = static_cast(1UL << 10U); #endif std::cout << "running: test_uintwide_t_0000128" << std::endl; test_uintwide_t_n_binary_ops_template<128U> test_uintwide_t_n_binary_ops_template_instance(count); // NOLINT(cppcoreguidelines-avoid-magic-numbers,readability-magic-numbers) const auto result_is_ok = test_uintwide_t_n_binary_ops_template_instance.do_test(test_uintwide_t_n_binary_ops_rounds); return result_is_ok; } auto test_uintwide_t_0000256() -> bool { #if !defined(UINTWIDE_T_REDUCE_TEST_DEPTH) constexpr auto count = static_cast(1UL << 13U); #else constexpr auto count = static_cast(1UL << 10U); #endif std::cout << "running: test_uintwide_t_0000256" << std::endl; test_uintwide_t_n_binary_ops_template<256U> test_uintwide_t_n_binary_ops_template_instance(count); // NOLINT(cppcoreguidelines-avoid-magic-numbers,readability-magic-numbers) const auto result_is_ok = test_uintwide_t_n_binary_ops_template_instance.do_test(test_uintwide_t_n_binary_ops_rounds); return result_is_ok; } #if defined(WIDE_INTEGER_HAS_LIMB_TYPE_UINT64) auto test_uintwide_t_0000256_limb_type_uint64_t() -> bool { #if !defined(UINTWIDE_T_REDUCE_TEST_DEPTH) constexpr auto count = static_cast(1UL << 13U); #else constexpr auto count = static_cast(1UL << 10U); #endif std::cout << "running: test_uintwide_t_0000256_limb_type_uint64_t" << std::endl; test_uintwide_t_n_binary_ops_template<256U, std::uint64_t> test_uintwide_t_n_binary_ops_template_instance(count); // NOLINT(cppcoreguidelines-avoid-magic-numbers,readability-magic-numbers) const auto result_is_ok = test_uintwide_t_n_binary_ops_template_instance.do_test(test_uintwide_t_n_binary_ops_rounds); return result_is_ok; } #endif auto test_uintwide_t_0000512() -> bool { #if !defined(UINTWIDE_T_REDUCE_TEST_DEPTH) constexpr auto count = static_cast(1UL << 13U); #else constexpr auto count = static_cast(1UL << 10U); #endif std::cout << "running: test_uintwide_t_0000512" << std::endl; test_uintwide_t_n_binary_ops_template<512U> test_uintwide_t_n_binary_ops_template_instance(count); // NOLINT(cppcoreguidelines-avoid-magic-numbers,readability-magic-numbers) const auto result_is_ok = test_uintwide_t_n_binary_ops_template_instance.do_test(test_uintwide_t_n_binary_ops_rounds); return result_is_ok; } auto test_uintwide_t_0000512_signed() -> bool { #if !defined(UINTWIDE_T_REDUCE_TEST_DEPTH) constexpr auto count = static_cast(1UL << 13U); #else constexpr auto count = static_cast(1UL << 10U); #endif std::cout << "running: test_uintwide_t_0000512_signed" << std::endl; test_uintwide_t_n_binary_ops_template_signed<512U> test_uintwide_t_n_binary_ops_template_signed_instance(count); // NOLINT(cppcoreguidelines-avoid-magic-numbers,readability-magic-numbers) const auto result_is_ok = test_uintwide_t_n_binary_ops_template_signed_instance.do_test(test_uintwide_t_n_binary_ops_rounds); return result_is_ok; } auto test_uintwide_t_0001024() -> bool { #if !defined(UINTWIDE_T_REDUCE_TEST_DEPTH) constexpr auto count = static_cast(1UL << 12U); #else constexpr auto count = static_cast(1UL << 9U); #endif std::cout << "running: test_uintwide_t_0001024" << std::endl; test_uintwide_t_n_binary_ops_template<1024U> test_uintwide_t_n_binary_ops_template_instance(count); // NOLINT(cppcoreguidelines-avoid-magic-numbers,readability-magic-numbers) const auto result_is_ok = test_uintwide_t_n_binary_ops_template_instance.do_test(test_uintwide_t_n_binary_ops_rounds); return result_is_ok; } auto test_uintwide_t_0002048() -> bool { #if !defined(UINTWIDE_T_REDUCE_TEST_DEPTH) constexpr auto count = static_cast(1UL << 11U); #else constexpr auto count = static_cast(1UL << 8U); #endif std::cout << "running: test_uintwide_t_0002048" << std::endl; test_uintwide_t_n_binary_ops_template<2048U> test_uintwide_t_n_binary_ops_template_instance(count); // NOLINT(cppcoreguidelines-avoid-magic-numbers,readability-magic-numbers) const auto result_is_ok = test_uintwide_t_n_binary_ops_template_instance.do_test(test_uintwide_t_n_binary_ops_rounds); return result_is_ok; } auto test_uintwide_t_0008192() -> bool { #if !defined(UINTWIDE_T_REDUCE_TEST_DEPTH) constexpr auto count = static_cast(1UL << 8U); #else constexpr auto count = static_cast(1UL << 5U); #endif std::cout << "running: test_uintwide_t_0008192" << std::endl; test_uintwide_t_n_binary_ops_template<8192U> test_uintwide_t_n_binary_ops_template_instance(count); // NOLINT(cppcoreguidelines-avoid-magic-numbers,readability-magic-numbers) const auto result_is_ok = test_uintwide_t_n_binary_ops_template_instance.do_test(test_uintwide_t_n_binary_ops_rounds); return result_is_ok; } #if defined(WIDE_INTEGER_HAS_LIMB_TYPE_UINT64) auto test_uintwide_t_0008192_limb_type_uint64_t() -> bool { #if !defined(UINTWIDE_T_REDUCE_TEST_DEPTH) constexpr auto count = static_cast(1UL << 8U); #else constexpr auto count = static_cast(1UL << 5U); #endif std::cout << "running: test_uintwide_t_0008192_limb_type_uint64_t" << std::endl; test_uintwide_t_n_binary_ops_template<8192U, std::uint64_t> test_uintwide_t_n_binary_ops_template_instance(count); // NOLINT(cppcoreguidelines-avoid-magic-numbers,readability-magic-numbers) const auto result_is_ok = test_uintwide_t_n_binary_ops_template_instance.do_test(test_uintwide_t_n_binary_ops_rounds); return result_is_ok; } #endif auto test_uintwide_t_0012288() -> bool { #if !defined(UINTWIDE_T_REDUCE_TEST_DEPTH) constexpr auto count = static_cast(1UL << 7U); #else constexpr auto count = static_cast(1UL << 4U); #endif std::cout << "running: test_uintwide_t_0012288" << std::endl; test_uintwide_t_n_binary_ops_template<12288U> test_uintwide_t_n_binary_ops_template_instance(count); // NOLINT(cppcoreguidelines-avoid-magic-numbers,readability-magic-numbers) const auto result_is_ok = test_uintwide_t_n_binary_ops_template_instance.do_test(test_uintwide_t_n_binary_ops_rounds); return result_is_ok; } auto test_uintwide_t_0032768() -> bool { #if !defined(UINTWIDE_T_REDUCE_TEST_DEPTH) constexpr auto count = static_cast(1UL << 7U); // NOLINT(cppcoreguidelines-avoid-magic-numbers,readability-magic-numbers) #else constexpr auto count = static_cast(1UL << 4U); // NOLINT(cppcoreguidelines-avoid-magic-numbers,readability-magic-numbers) #endif std::cout << "running: test_uintwide_t_0032768" << std::endl; test_uintwide_t_n_binary_ops_template<32768U> test_uintwide_t_n_binary_ops_template_instance(count); // NOLINT(cppcoreguidelines-avoid-magic-numbers,readability-magic-numbers) const auto result_is_ok = test_uintwide_t_n_binary_ops_template_instance.do_test(test_uintwide_t_n_binary_ops_rounds); return result_is_ok; } auto test_uintwide_t_0065536_alloc() -> bool { #if !defined(UINTWIDE_T_REDUCE_TEST_DEPTH) constexpr auto count = static_cast(1UL << 5U); // NOLINT(cppcoreguidelines-avoid-magic-numbers,readability-magic-numbers) #else constexpr auto count = static_cast(1UL << 2U); // NOLINT(cppcoreguidelines-avoid-magic-numbers,readability-magic-numbers) #endif std::cout << "running: test_uintwide_t_0065536_alloc" << std::endl; test_uintwide_t_n_binary_ops_template<65536U, std::uint32_t, std::allocator> test_uintwide_t_n_binary_ops_template_instance(count); // NOLINT(cppcoreguidelines-avoid-magic-numbers,readability-magic-numbers) const auto result_is_ok = test_uintwide_t_n_binary_ops_template_instance.do_test(test_uintwide_t_n_binary_ops_rounds); return result_is_ok; } auto test_uintwide_t_0008192_by_0012288() -> bool { #if !defined(UINTWIDE_T_REDUCE_TEST_DEPTH) constexpr auto count = static_cast(1UL << 7U); // NOLINT(cppcoreguidelines-avoid-magic-numbers,readability-magic-numbers) #else constexpr auto count = static_cast(1UL << 4U); // NOLINT(cppcoreguidelines-avoid-magic-numbers,readability-magic-numbers) #endif std::cout << "running: test_uintwide_t_0008192_by_0012288" << std::endl; test_uintwide_t_n_binary_ops_mul_n_by_m_template<8192U, 12288U> test_uintwide_t_n_binary_ops_template_instance(count); // NOLINT(cppcoreguidelines-avoid-magic-numbers,readability-magic-numbers) const auto result_is_ok = test_uintwide_t_n_binary_ops_template_instance.do_test(test_uintwide_t_n_binary_ops_rounds); return result_is_ok; } auto test_uintwide_t_0012288_by_0008192() -> bool { #if !defined(UINTWIDE_T_REDUCE_TEST_DEPTH) constexpr auto count = static_cast(1UL << 7U); // NOLINT(cppcoreguidelines-avoid-magic-numbers,readability-magic-numbers) #else constexpr auto count = static_cast(1UL << 4U); // NOLINT(cppcoreguidelines-avoid-magic-numbers,readability-magic-numbers) #endif std::cout << "running: test_uintwide_t_0012288_by_0008192" << std::endl; test_uintwide_t_n_binary_ops_mul_n_by_m_template<12288U, 8192U> test_uintwide_t_n_binary_ops_template_instance(count); // NOLINT(cppcoreguidelines-avoid-magic-numbers,readability-magic-numbers) const auto result_is_ok = test_uintwide_t_n_binary_ops_template_instance.do_test(test_uintwide_t_n_binary_ops_rounds); return result_is_ok; } auto test_uintwide_t_0000032_by_0000032_4_by_4() -> bool { std::cout << "running: test_uintwide_t_0000032_by_0000032_4_by_4" << std::endl; test_uintwide_t_n_binary_ops_mul_div_4_by_4_template<32U, std::uint8_t> test_uintwide_t_n_binary_ops_template_instance(test_uintwide_t_n_binary_ops_4_by_4_cases); // NOLINT(cppcoreguidelines-avoid-magic-numbers,readability-magic-numbers) const auto result_is_ok = test_uintwide_t_n_binary_ops_template_instance.do_test(test_uintwide_t_n_binary_ops_rounds); return result_is_ok; } auto test_uintwide_t_0000064_by_0000064_4_by_4() -> bool { std::cout << "running: test_uintwide_t_0000064_by_0000064_4_by_4" << std::endl; test_uintwide_t_n_binary_ops_mul_div_4_by_4_template<64U, std::uint16_t> test_uintwide_t_n_binary_ops_template_instance(test_uintwide_t_n_binary_ops_4_by_4_cases); // NOLINT(cppcoreguidelines-avoid-magic-numbers,readability-magic-numbers) const auto result_is_ok = test_uintwide_t_n_binary_ops_template_instance.do_test(test_uintwide_t_n_binary_ops_rounds); return result_is_ok; } auto run() -> bool // NOLINT(readability-function-cognitive-complexity) { #if (BOOST_VERSION < 107900) using boost_wrapexcept_lexical_type = ::boost::wrapexcept<::boost::bad_lexical_cast>; using boost_wrapexcept_runtime_type = ::boost::wrapexcept; #endif using stopwatch_type = concurrency::stopwatch; stopwatch_type my_stopwatch { }; bool result_is_ok = true; #if ((BOOST_VERSION < 107900) || ((BOOST_VERSION >= 108000) && !defined(BOOST_NO_EXCEPTIONS))) try { #endif result_is_ok = (test_uintwide_t_small_bits() && result_is_ok); std::cout << "result_is_ok: " << std::boolalpha << result_is_ok << std::endl; result_is_ok = (test_uintwide_t_boost_backend() && result_is_ok); std::cout << "result_is_ok: " << std::boolalpha << result_is_ok << std::endl; result_is_ok = (test_uintwide_t_examples() && result_is_ok); std::cout << "result_is_ok: " << std::boolalpha << result_is_ok << std::endl; result_is_ok = (test_uintwide_t_edge_cases() && result_is_ok); std::cout << "result_is_ok: " << std::boolalpha << result_is_ok << std::endl; result_is_ok = (test_uintwide_t_float_convert() && result_is_ok); std::cout << "result_is_ok: " << std::boolalpha << result_is_ok << std::endl; result_is_ok = (test_uintwide_t_int_convert() && result_is_ok); std::cout << "result_is_ok: " << std::boolalpha << result_is_ok << std::endl; result_is_ok = (test_uintwide_t_spot_values() && result_is_ok); std::cout << "result_is_ok: " << std::boolalpha << result_is_ok << std::endl; result_is_ok = (test_uintwide_t_0000024() && result_is_ok); std::cout << "result_is_ok: " << std::boolalpha << result_is_ok << std::endl; result_is_ok = (test_uintwide_t_0000048() && result_is_ok); std::cout << "result_is_ok: " << std::boolalpha << result_is_ok << std::endl; result_is_ok = (test_uintwide_t_0000064() && result_is_ok); std::cout << "result_is_ok: " << std::boolalpha << result_is_ok << std::endl; result_is_ok = (test_uintwide_t_0000064_signed() && result_is_ok); std::cout << "result_is_ok: " << std::boolalpha << result_is_ok << std::endl; result_is_ok = (test_uintwide_t_0000096() && result_is_ok); std::cout << "result_is_ok: " << std::boolalpha << result_is_ok << std::endl; result_is_ok = (test_uintwide_t_0000128() && result_is_ok); std::cout << "result_is_ok: " << std::boolalpha << result_is_ok << std::endl; result_is_ok = (test_uintwide_t_0000256() && result_is_ok); std::cout << "result_is_ok: " << std::boolalpha << result_is_ok << std::endl; #if defined(WIDE_INTEGER_HAS_LIMB_TYPE_UINT64) result_is_ok = (test_uintwide_t_0000256_limb_type_uint64_t() && result_is_ok); std::cout << "result_is_ok: " << std::boolalpha << result_is_ok << std::endl; #endif result_is_ok = (test_uintwide_t_0000512() && result_is_ok); std::cout << "result_is_ok: " << std::boolalpha << result_is_ok << std::endl; result_is_ok = (test_uintwide_t_0000512_signed() && result_is_ok); std::cout << "result_is_ok: " << std::boolalpha << result_is_ok << std::endl; result_is_ok = (test_uintwide_t_0001024() && result_is_ok); std::cout << "result_is_ok: " << std::boolalpha << result_is_ok << std::endl; result_is_ok = (test_uintwide_t_0002048() && result_is_ok); std::cout << "result_is_ok: " << std::boolalpha << result_is_ok << std::endl; result_is_ok = (test_uintwide_t_0008192() && result_is_ok); std::cout << "result_is_ok: " << std::boolalpha << result_is_ok << std::endl; #if defined(WIDE_INTEGER_HAS_LIMB_TYPE_UINT64) result_is_ok = (test_uintwide_t_0008192_limb_type_uint64_t() && result_is_ok); std::cout << "result_is_ok: " << std::boolalpha << result_is_ok << std::endl; #endif result_is_ok = (test_uintwide_t_0012288() && result_is_ok); std::cout << "result_is_ok: " << std::boolalpha << result_is_ok << std::endl; result_is_ok = (test_uintwide_t_0032768() && result_is_ok); std::cout << "result_is_ok: " << std::boolalpha << result_is_ok << std::endl; result_is_ok = (test_uintwide_t_0065536_alloc() && result_is_ok); std::cout << "result_is_ok: " << std::boolalpha << result_is_ok << std::endl; result_is_ok = (test_uintwide_t_0008192_by_0012288() && result_is_ok); std::cout << "result_is_ok: " << std::boolalpha << result_is_ok << std::endl; result_is_ok = (test_uintwide_t_0012288_by_0008192() && result_is_ok); std::cout << "result_is_ok: " << std::boolalpha << result_is_ok << std::endl; result_is_ok = (test_uintwide_t_0000032_by_0000032_4_by_4() && result_is_ok); std::cout << "result_is_ok: " << std::boolalpha << result_is_ok << std::endl; result_is_ok = (test_uintwide_t_0000064_by_0000064_4_by_4() && result_is_ok); std::cout << "result_is_ok: " << std::boolalpha << result_is_ok << std::endl; #if ((BOOST_VERSION < 107900) || ((BOOST_VERSION >= 108000) && !defined(BOOST_NO_EXCEPTIONS))) } catch(boost_wrapexcept_lexical_type& e) { result_is_ok = false; std::cout << "Exception: boost_wrapexcept_lexical_type: " << e.what() << std::endl; } catch(boost_wrapexcept_runtime_type& e) { result_is_ok = false; std::cout << "Exception: boost_wrapexcept_runtime_type: " << e.what() << std::endl; } #endif const auto execution_time = stopwatch_type::elapsed_time(my_stopwatch); { std::stringstream strm { }; strm << "result_is_ok: " << std::boolalpha << result_is_ok << ", time: " << std::fixed << std::setprecision(1) << execution_time << "s" ; std::cout << strm.str() << std::endl; } return result_is_ok; } } // namespace local auto main() -> int // NOLINT(bugprone-exception-escape) { const bool result_is_ok { local::run() }; const int result_of_main { (result_is_ok ? static_cast(INT8_C(0)) : static_cast(INT8_C(-1))) }; std::cout << "result_of_main: " << result_of_main << std::endl; return result_of_main; } #if (defined(__GNUC__) && !defined(__clang__) && (__GNUC__ >= 12)) #pragma GCC diagnostic pop #endif #if (BOOST_VERSION < 107900) #if defined(__GNUC__) #pragma GCC diagnostic pop #pragma GCC diagnostic pop #endif #endif #if (((BOOST_VERSION == 108000) || (BOOST_VERSION == 108100)) && defined(BOOST_NO_EXCEPTIONS)) #if defined(__clang__) #pragma GCC diagnostic pop #endif #if defined(_MSC_VER) #pragma warning(pop) #endif #endif ================================================ FILE: test/test.hpp ================================================ /////////////////////////////////////////////////////////////// // Copyright 2012 John Maddock. // Copyright 2022 - 2025 Christopher Kormanyos. // Distributed under the Boost // Software License, Version 1.0. (See accompanying file // LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt // #ifndef BOOST_MULTIPRECISION_TEST_HPP #define BOOST_MULTIPRECISION_TEST_HPP #include #include #include #include #include #include #include #include namespace detail { template constexpr auto abs(const T& a) -> typename std::enable_if_t::value || boost::multiprecision::is_unsigned_number::value), T> { return a < 0 ? -a : a; } template constexpr auto abs(const T& a) -> typename std::enable_if_t::value || boost::multiprecision::is_unsigned_number::value, T> { return a; } } // namespace detail template constexpr auto relative_error(T a, T b) -> typename std::enable_if_t::value == boost::multiprecision::number_kind_integer, T> { return a > b ? a - b : b - a; } template constexpr auto relative_error(T a, T b) -> typename std::enable_if_t::value == boost::multiprecision::number_kind_integer) || boost::multiprecision::is_interval_number::value), T> { using ::detail::abs; using std::abs; T min_val = (std::numeric_limits::min)(); T max_val = (std::numeric_limits::max)(); if ((a != 0) && (b != 0)) { if (a == b) return 0; // TODO: use isfinite: if (abs(b) >= max_val) { if (abs(a) >= max_val) return 0; // one infinity is as good as another! } // If the result is denormalised, treat all denorms as equivalent: if ((a < min_val) && (a > 0)) a = min_val; else if ((a > -min_val) && (a < 0)) a = -min_val; if ((b < min_val) && (b > 0)) b = min_val; else if ((b > -min_val) && (b < 0)) b = -min_val; return (std::max)(abs(T((a - b) / a)), abs(T((a - b) / b))) / std::numeric_limits::epsilon(); } // Handle special case where one or both are zero: if (min_val == 0) return abs(T(a - b)); if (abs(a) < min_val) a = min_val; if (abs(b) < min_val) b = min_val; return (std::max)(abs(T((a - b) / a)), abs(T((a - b) / b))) / std::numeric_limits::epsilon(); } template constexpr auto relative_error(T a, T b) -> typename std::enable_if_t::value, T> { typename boost::multiprecision::component_type::type am = median(a); typename boost::multiprecision::component_type::type bm = median(b); return relative_error::type>(am, bm); } template constexpr auto relative_error(T a, U b) -> typename std::conditional_t::value, U, T> { typedef typename std::conditional::value, U, T>::type cast_type; return relative_error(static_cast(a), static_cast(b)); } enum { warn_on_fail, error_on_fail, abort_on_fail }; template T epsilon_of(const T&) { static_assert(std::numeric_limits::is_specialized, "No numeric_limits support"); return std::numeric_limits::is_integer ? static_cast(1) : std::numeric_limits::epsilon(); } template int digits_of(const T&) { return std::numeric_limits::is_specialized ? std::numeric_limits::digits10 + 3 : std::numeric_limits::digits10 + 3; } std::ostream& report_where(const char* file, int line, const char* function) { if (function) BOOST_LIGHTWEIGHT_TEST_OSTREAM << "In function: " << function << std::endl; BOOST_LIGHTWEIGHT_TEST_OSTREAM << file << ":" << line; return BOOST_LIGHTWEIGHT_TEST_OSTREAM; } #define BOOST_MP_REPORT_WHERE report_where(__FILE__, __LINE__, BOOST_CURRENT_FUNCTION) void report_severity(int severity) { if (severity == error_on_fail) ++boost::detail::test_errors(); else if (severity == abort_on_fail) { ++boost::detail::test_errors(); abort(); } } #define BOOST_MP_REPORT_SEVERITY(severity) report_severity(severity) template void report_unexpected_exception(const E& e, int severity, const char* file, int line, const char* function) { report_where(file, line, function) << " Unexpected exception of type " << typeid(e).name() << std::endl; BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Errot message was: " << e.what() << std::endl; BOOST_MP_REPORT_SEVERITY(severity); } #ifdef BOOST_HAS_INT128 #if (defined(__GNUC__) && !defined(__clang__)) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wpedantic" #endif std::ostream& operator<<(std::ostream& os, __int128 val) { std::stringstream ss; ss << std::hex << "0x" << static_cast(static_cast(val) >> 64) << static_cast(val); return os << ss.str(); } std::ostream& operator<<(std::ostream& os, unsigned __int128 val) { std::stringstream ss; ss << std::hex << "0x" << static_cast(val >> 64) << static_cast(val); return os << ss.str(); } #if (defined(__GNUC__) && !defined(__clang__)) #pragma GCC diagnostic pop #endif #endif #ifdef BOOST_HAS_FLOAT128 std::ostream& operator<<(std::ostream& os, __float128 f) { return os << static_cast(f); } #endif #ifndef BOOST_NO_EXCEPTIONS #define BOOST_MP_UNEXPECTED_EXCEPTION_CHECK(severity) \ catch (const std::exception& e) \ { \ report_unexpected_exception(e, severity, __FILE__, __LINE__, BOOST_CURRENT_FUNCTION); \ } \ catch (...) \ { \ std::cout << "Exception of unknown type was thrown" << std::endl; \ report_severity(severity); \ } #define BOOST_MP_TEST_TRY try #else #define BOOST_MP_UNEXPECTED_EXCEPTION_CHECK(severity) #define BOOST_MP_TEST_TRY #endif #define BOOST_CHECK_IMP(x, severity) \ BOOST_MP_TEST_TRY \ { \ if (x) \ { \ } \ else \ { \ BOOST_MP_REPORT_WHERE << " Failed predicate: " << BOOST_STRINGIZE(x) << std::endl; \ BOOST_MP_REPORT_SEVERITY(severity); \ } \ } \ BOOST_MP_UNEXPECTED_EXCEPTION_CHECK(severity) #define BOOST_CHECK(x) BOOST_CHECK_IMP(x, error_on_fail) #define BOOST_WARN(x) BOOST_CHECK_IMP(x, warn_on_fail) #define BOOST_REQUIRE(x) BOOST_CHECK_IMP(x, abort_on_fail) #define BOOST_CLOSE_IMP(x, y, tol, severity) \ BOOST_MP_TEST_TRY \ { \ if (relative_error(x, y) > tol) \ { \ BOOST_MP_REPORT_WHERE << " Failed check for closeness: \n" \ << std::setprecision(digits_of(x)) << std::scientific \ << "Value of LHS was: " << x << "\n" \ << "Value of RHS was: " << y << "\n" \ << std::setprecision(5) << std::fixed \ << "Relative error was: " << relative_error(x, y) << "eps\n" \ << "Tolerance was: " << tol << "eps" << std::endl; \ BOOST_MP_REPORT_SEVERITY(severity); \ } \ } \ BOOST_MP_UNEXPECTED_EXCEPTION_CHECK(severity) #define BOOST_EQUAL_IMP(x, y, severity) \ BOOST_MP_TEST_TRY \ { \ if (!((x) == (y))) \ { \ BOOST_MP_REPORT_WHERE << " Failed check for equality: \n" \ << std::setprecision(digits_of(x)) << std::scientific \ << "Value of LHS was: " << (x) << "\n" \ << "Value of RHS was: " << (y) << "\n" \ << std::setprecision(3) << std::endl; \ BOOST_MP_REPORT_SEVERITY(severity); \ } \ } \ BOOST_MP_UNEXPECTED_EXCEPTION_CHECK(severity) #define BOOST_NE_IMP(x, y, severity) \ BOOST_MP_TEST_TRY \ { \ if (!(x != y)) \ { \ BOOST_MP_REPORT_WHERE << " Failed check for non-equality: \n" \ << std::setprecision(digits_of(x)) << std::scientific \ << "Value of LHS was: " << x << "\n" \ << "Value of RHS was: " << y << "\n" \ << std::setprecision(3) << std::endl; \ BOOST_MP_REPORT_SEVERITY(severity); \ } \ } \ BOOST_MP_UNEXPECTED_EXCEPTION_CHECK(severity) #define BOOST_LT_IMP(x, y, severity) \ BOOST_MP_TEST_TRY \ { \ if (!(x < y)) \ { \ BOOST_MP_REPORT_WHERE << " Failed check for less than: \n" \ << std::setprecision(digits_of(x)) << std::scientific \ << "Value of LHS was: " << x << "\n" \ << "Value of RHS was: " << y << "\n" \ << std::setprecision(3) << std::endl; \ BOOST_MP_REPORT_SEVERITY(severity); \ } \ } \ BOOST_MP_UNEXPECTED_EXCEPTION_CHECK(severity) #define BOOST_GT_IMP(x, y, severity) \ BOOST_MP_TEST_TRY \ { \ if (!(x > y)) \ { \ BOOST_MP_REPORT_WHERE << " Failed check for greater than: \n" \ << std::setprecision(digits_of(x)) << std::scientific \ << "Value of LHS was: " << x << "\n" \ << "Value of RHS was: " << y << "\n" \ << std::setprecision(3) << std::endl; \ BOOST_MP_REPORT_SEVERITY(severity); \ } \ } \ BOOST_MP_UNEXPECTED_EXCEPTION_CHECK(severity) #define BOOST_LE_IMP(x, y, severity) \ BOOST_MP_TEST_TRY \ { \ if (!(x <= y)) \ { \ BOOST_MP_REPORT_WHERE << " Failed check for less-than-equal-to: \n" \ << std::setprecision(digits_of(x)) << std::scientific \ << "Value of LHS was: " << x << "\n" \ << "Value of RHS was: " << y << "\n" \ << std::setprecision(3) << std::endl; \ BOOST_MP_REPORT_SEVERITY(severity); \ } \ } \ BOOST_MP_UNEXPECTED_EXCEPTION_CHECK(severity) #define BOOST_GE_IMP(x, y, severity) \ BOOST_MP_TEST_TRY \ { \ if (!(x >= y)) \ { \ BOOST_MP_REPORT_WHERE << " Failed check for greater-than-equal-to \n" \ << std::setprecision(digits_of(x)) << std::scientific \ << "Value of LHS was: " << x << "\n" \ << "Value of RHS was: " << y << "\n" \ << std::setprecision(3) << std::endl; \ BOOST_MP_REPORT_SEVERITY(severity); \ } \ } \ BOOST_MP_UNEXPECTED_EXCEPTION_CHECK(severity) #ifndef BOOST_NO_EXCEPTIONS #define BOOST_MT_CHECK_THROW_IMP(x, E, severity) \ BOOST_MP_TEST_TRY \ { \ x; \ BOOST_MP_REPORT_WHERE << " Expected exception not thrown in expression " << BOOST_STRINGIZE(x) << std::endl; \ BOOST_MP_REPORT_SEVERITY(severity); \ } \ catch (const E&) {} \ BOOST_MP_UNEXPECTED_EXCEPTION_CHECK(severity) #else #define BOOST_MT_CHECK_THROW_IMP(x, E, severity) #endif #define BOOST_CHECK_CLOSE(x, y, tol) BOOST_CLOSE_IMP(x, y, ((tol / (100 * epsilon_of(x)))), error_on_fail) #define BOOST_WARN_CLOSE(x, y, tol) BOOST_CLOSE_IMP(x, y, (tol / (100 * epsilon_of(x))), warn_on_fail) #define BOOST_REQUIRE_CLOSE(x, y, tol) BOOST_CLOSE_IMP(x, y, (tol / (100 * epsilon_of(x))), abort_on_fail) #define BOOST_CHECK_CLOSE_FRACTION(x, y, tol) BOOST_CLOSE_IMP(x, y, ((tol / (epsilon_of(x)))), error_on_fail) #define BOOST_WARN_CLOSE_FRACTION(x, y, tol) BOOST_CLOSE_IMP(x, y, (tol / (epsilon_of(x))), warn_on_fail) #define BOOST_REQUIRE_CLOSE_FRACTION(x, y, tol) BOOST_CLOSE_IMP(x, y, (tol / (epsilon_of(x))), abort_on_fail) #define BOOST_CHECK_EQUAL(x, y) BOOST_EQUAL_IMP(x, y, error_on_fail) #define BOOST_WARN_EQUAL(x, y) BOOST_EQUAL_IMP(x, y, warn_on_fail) #define BOOST_REQUIRE_EQUAL(x, y) BOOST_EQUAL_IMP(x, y, abort_on_fail) #define BOOST_CHECK_NE(x, y) BOOST_NE_IMP(x, y, error_on_fail) #define BOOST_WARN_NE(x, y) BOOST_NE_IMP(x, y, warn_on_fail) #define BOOST_REQUIRE_NE(x, y) BOOST_NE_IMP(x, y, abort_on_fail) #define BOOST_CHECK_LT(x, y) BOOST_LT_IMP(x, y, error_on_fail) #define BOOST_WARN_LT(x, y) BOOST_LT_IMP(x, y, warn_on_fail) #define BOOST_REQUIRE_LT(x, y) BOOST_LT_IMP(x, y, abort_on_fail) #define BOOST_CHECK_GT(x, y) BOOST_GT_IMP(x, y, error_on_fail) #define BOOST_WARN_GT(x, y) BOOST_GT_IMP(x, y, warn_on_fail) #define BOOST_REQUIRE_GT(x, y) BOOST_GT_IMP(x, y, abort_on_fail) #define BOOST_CHECK_LE(x, y) BOOST_LE_IMP(x, y, error_on_fail) #define BOOST_WARN_LE(x, y) BOOST_LE_IMP(x, y, warn_on_fail) #define BOOST_REQUIRE_LE(x, y) BOOST_LE_IMP(x, y, abort_on_fail) #define BOOST_CHECK_GE(x, y) BOOST_GE_IMP(x, y, error_on_fail) #define BOOST_WARN_GE(x, y) BOOST_GE_IMP(x, y, warn_on_fail) #define BOOST_REQUIRE_GE(x, y) BOOST_GE_IMP(x, y, abort_on_fail) #define BOOST_CHECK_THROW(x, E) BOOST_MT_CHECK_THROW_IMP(x, E, error_on_fail) #define BOOST_WARN_THROW(x, E) BOOST_MT_CHECK_THROW_IMP(x, E, warn_on_fail) #define BOOST_REQUIRE_THROW(x, E) BOOST_MT_CHECK_THROW_IMP(x, E, abort_on_fail) #endif ================================================ FILE: test/test_arithmetic.hpp ================================================ /////////////////////////////////////////////////////////////// // Copyright 2012 John Maddock. // Copyright 2022 - 2025 Christopher Kormanyos. // Distributed under the Boost // Software License, Version 1.0. (See accompanying file // LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt #ifdef TEST_VLD #include #endif #include #ifndef BOOST_MP_STANDALONE #include #include #include #endif #include #include #include #include template struct is_boost_rational : public std::integral_constant {}; template struct is_checked_cpp_int : public std::integral_constant {}; #ifdef BOOST_MSVC // warning C4127: conditional expression is constant #pragma warning(disable : 4127) #endif // // This works around some platforms which have missing typeinfo // for __int128 and/or __float128: // template const char* name_of() { return typeid(T).name(); } #ifdef BOOST_HAS_INT128 #if (defined(__GNUC__) && !defined(__clang__)) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wpedantic" #endif template <> const char* name_of<__int128>() { return "__int128"; } template <> const char* name_of() { return "unsigned __int128"; } #if (defined(__GNUC__) && !defined(__clang__)) #pragma GCC diagnostic pop #endif #endif #ifdef BOOST_HAS_FLOAT128 //template <> //const char* name_of<__float128>() //{ // return "__float128"; //} #endif #ifndef BOOST_MP_STANDALONE template Target checked_lexical_cast(const Source& val) { #ifndef BOOST_NO_EXCEPTIONS try { #endif return boost::lexical_cast(val); #ifndef BOOST_NO_EXCEPTIONS } catch (...) { std::cerr << "Error in lexical cast\nSource type = " << name_of() << " \"" << val << "\"\n"; std::cerr << "Target type = " << name_of() << std::endl; throw; } #endif } #endif bool isfloat(float) { return true; } bool isfloat(double) { return true; } bool isfloat(long double) { return true; } template bool isfloat(T) { return false; } namespace detail { template typename boost::multiprecision::detail::expression::result_type abs(boost::multiprecision::detail::expression const& v) { typedef typename boost::multiprecision::detail::expression::result_type result_type; return v < 0 ? result_type(-v) : result_type(v); } } // namespace detail template struct is_twos_complement_integer : public std::integral_constant {}; template struct related_type { typedef T type; }; template void test_comparisons(Val, Val, const std::integral_constant&) {} int normalize_compare_result(int r) { return r > 0 ? 1 : r < 0 ? -1 : 0; } enum unscoped_enum { one = 1, two = 2, three = 3, }; enum struct scoped_enum { four = 4, five = 5, six = 6, }; template typename std::enable_if::value>::type test_enum_conversions() { Real r1(one); BOOST_CHECK_EQUAL(r1, 1); Real r2(scoped_enum::four); BOOST_CHECK_EQUAL(r2, 4); r1 = two; BOOST_CHECK_EQUAL(r1, 2); r1.assign(scoped_enum::five); BOOST_CHECK_EQUAL(r1, 5); r1.assign(two); BOOST_CHECK_EQUAL(static_cast(r1), two); BOOST_CHECK(static_cast(r2) == scoped_enum::four); } template typename std::enable_if::value>::type test_enum_conversions() {} template typename std::enable_if::value != boost::multiprecision::number_kind_complex>::type test_comparisons(Val a, Val b, const std::integral_constant&) { Real r1(a); Real r2(b); Real z(1); int cr = a < b ? -1 : a > b ? 1 : 0; BOOST_CHECK_EQUAL(r1 == r2, a == b); BOOST_CHECK_EQUAL(r1 != r2, a != b); BOOST_CHECK_EQUAL(r1 <= r2, a <= b); BOOST_CHECK_EQUAL(r1 < r2, a < b); BOOST_CHECK_EQUAL(r1 >= r2, a >= b); BOOST_CHECK_EQUAL(r1 > r2, a > b); BOOST_CHECK_EQUAL(r1 == b, a == b); BOOST_CHECK_EQUAL(r1 != b, a != b); BOOST_CHECK_EQUAL(r1 <= b, a <= b); BOOST_CHECK_EQUAL(r1 < b, a < b); BOOST_CHECK_EQUAL(r1 >= b, a >= b); BOOST_CHECK_EQUAL(r1 > b, a > b); BOOST_CHECK_EQUAL(a == r2, a == b); BOOST_CHECK_EQUAL(a != r2, a != b); BOOST_CHECK_EQUAL(a <= r2, a <= b); BOOST_CHECK_EQUAL(a < r2, a < b); BOOST_CHECK_EQUAL(a >= r2, a >= b); BOOST_CHECK_EQUAL(a > r2, a > b); BOOST_CHECK_EQUAL(r1 * z == r2, a == b); BOOST_CHECK_EQUAL(r1 * z != r2, a != b); BOOST_CHECK_EQUAL(r1 * z <= r2, a <= b); BOOST_CHECK_EQUAL(r1 * z < r2, a < b); BOOST_CHECK_EQUAL(r1 * z >= r2, a >= b); BOOST_CHECK_EQUAL(r1 * z > r2, a > b); BOOST_CHECK_EQUAL(r1 == r2 * z, a == b); BOOST_CHECK_EQUAL(r1 != r2 * z, a != b); BOOST_CHECK_EQUAL(r1 <= r2 * z, a <= b); BOOST_CHECK_EQUAL(r1 < r2 * z, a < b); BOOST_CHECK_EQUAL(r1 >= r2 * z, a >= b); BOOST_CHECK_EQUAL(r1 > r2 * z, a > b); BOOST_CHECK_EQUAL(r1 * z == r2 * z, a == b); BOOST_CHECK_EQUAL(r1 * z != r2 * z, a != b); BOOST_CHECK_EQUAL(r1 * z <= r2 * z, a <= b); BOOST_CHECK_EQUAL(r1 * z < r2 * z, a < b); BOOST_CHECK_EQUAL(r1 * z >= r2 * z, a >= b); BOOST_CHECK_EQUAL(r1 * z > r2 * z, a > b); BOOST_CHECK_EQUAL(r1 * z == b, a == b); BOOST_CHECK_EQUAL(r1 * z != b, a != b); BOOST_CHECK_EQUAL(r1 * z <= b, a <= b); BOOST_CHECK_EQUAL(r1 * z < b, a < b); BOOST_CHECK_EQUAL(r1 * z >= b, a >= b); BOOST_CHECK_EQUAL(r1 * z > b, a > b); BOOST_CHECK_EQUAL(a == r2 * z, a == b); BOOST_CHECK_EQUAL(a != r2 * z, a != b); BOOST_CHECK_EQUAL(a <= r2 * z, a <= b); BOOST_CHECK_EQUAL(a < r2 * z, a < b); BOOST_CHECK_EQUAL(a >= r2 * z, a >= b); BOOST_CHECK_EQUAL(a > r2 * z, a > b); BOOST_CHECK_EQUAL(normalize_compare_result(r1.compare(r2)), cr); BOOST_CHECK_EQUAL(normalize_compare_result(r2.compare(r1)), -cr); BOOST_CHECK_EQUAL(normalize_compare_result(r1.compare(b)), cr); BOOST_CHECK_EQUAL(normalize_compare_result(r2.compare(a)), -cr); } template typename std::enable_if::value == boost::multiprecision::number_kind_complex>::type test_comparisons(Val a, Val b, const std::integral_constant&) { Real r1(a); Real r2(b); Real z(1); int cr = a < b ? -1 : a > b ? 1 : 0; (void)cr; BOOST_CHECK_EQUAL(r1 == r2, a == b); BOOST_CHECK_EQUAL(r1 != r2, a != b); BOOST_CHECK_EQUAL(r1 == b, a == b); BOOST_CHECK_EQUAL(r1 != b, a != b); BOOST_CHECK_EQUAL(a == r2, a == b); BOOST_CHECK_EQUAL(a != r2, a != b); BOOST_CHECK_EQUAL(r1 * z == r2, a == b); BOOST_CHECK_EQUAL(r1 * z != r2, a != b); BOOST_CHECK_EQUAL(r1 == r2 * z, a == b); BOOST_CHECK_EQUAL(r1 != r2 * z, a != b); BOOST_CHECK_EQUAL(r1 * z == r2 * z, a == b); BOOST_CHECK_EQUAL(r1 * z != r2 * z, a != b); BOOST_CHECK_EQUAL(r1 * z == b, a == b); BOOST_CHECK_EQUAL(r1 * z != b, a != b); BOOST_CHECK_EQUAL(a == r2 * z, a == b); BOOST_CHECK_EQUAL(a != r2 * z, a != b); if (r1 == r2) { BOOST_CHECK_EQUAL(normalize_compare_result(r1.compare(r2)), 0); BOOST_CHECK_EQUAL(normalize_compare_result(r2.compare(r1)), 0); BOOST_CHECK_EQUAL(normalize_compare_result(r1.compare(b)), 0); BOOST_CHECK_EQUAL(normalize_compare_result(r2.compare(a)), 0); } else { BOOST_CHECK_NE(normalize_compare_result(r1.compare(r2)), 0); BOOST_CHECK_NE(normalize_compare_result(r2.compare(r1)), 0); BOOST_CHECK_NE(normalize_compare_result(r1.compare(b)), 0); BOOST_CHECK_NE(normalize_compare_result(r2.compare(a)), 0); } } template void test_conditional(Real v, Exp e) { // // Verify that Exp is usable in Boolean contexts, and has the same value as v: // if (e) { BOOST_CHECK(v); } else { BOOST_CHECK(!v); } if (!e) { BOOST_CHECK(!v); } else { BOOST_CHECK(v); } } template void test_complement(Real a, Real b, Real c, const std::integral_constant&) { int i = 1020304; int j = 56789123; int sign_mask = ~0; BOOST_IF_CONSTEXPR (std::numeric_limits::is_signed) { BOOST_CHECK_EQUAL(~a, (~i & sign_mask)); c = a & ~b; BOOST_CHECK_EQUAL(c, (i & (~j & sign_mask))); c = ~(a | b); BOOST_CHECK_EQUAL(c, (~(i | j) & sign_mask)); } else { BOOST_CHECK_EQUAL((~a & a), 0); } } template void test_complement(Real, Real, Real, const std::integral_constant&) { } template void test_integer_ops(const T&) {} template void test_rational(const std::integral_constant&) { Real a(2); a /= 3; BOOST_CHECK_EQUAL(numerator(a), 2); BOOST_CHECK_EQUAL(denominator(a), 3); Real b(4); b /= 6; BOOST_CHECK_EQUAL(a, b); // // Check IO code: // std::stringstream ss; ss << a; ss >> b; BOOST_CHECK_EQUAL(a, b); } template void test_rational_signed(const std::integral_constant&) { Real three = -3; BOOST_CHECK_EQUAL(static_cast(three), -3); BOOST_CHECK_EQUAL(static_cast(three), -3); BOOST_CHECK_EQUAL(static_cast(three), -3); } template void test_rational_signed(const std::integral_constant&) { } template void test_rational(const std::integral_constant&) { Real a(2); a /= 3; BOOST_CHECK_EQUAL(numerator(a), 2); BOOST_CHECK_EQUAL(denominator(a), 3); Real b(4); b /= 6; BOOST_CHECK_EQUAL(a, b); #if 0//ndef BOOST_NO_EXCEPTIONS BOOST_CHECK_THROW(Real(a / 0), std::overflow_error); BOOST_CHECK_THROW(Real("3.14"), std::runtime_error); #endif b = Real("2/3"); BOOST_CHECK_EQUAL(a, b); // // Check IO code: // std::stringstream ss; ss << a; ss >> b; BOOST_CHECK_EQUAL(a, b); // // Conversion to integer, see https://github.com/boostorg/multiprecision/issues/342. // Real three(10, 3); BOOST_CHECK_EQUAL(static_cast(three), 3); BOOST_CHECK_EQUAL(static_cast(three), 3); BOOST_CHECK_EQUAL(static_cast(three), 3); test_rational_signed(std::integral_constant::is_signed>()); } template void test_integer_ops(const std::integral_constant&) { test_rational(is_boost_rational()); } template void test_signed_integer_ops(const std::integral_constant&) { Real a(20); Real b(7); Real c(5); BOOST_CHECK_EQUAL(-a % c, 0); BOOST_CHECK_EQUAL(-a % b, -20 % 7); BOOST_CHECK_EQUAL(-a % -b, -20 % -7); BOOST_CHECK_EQUAL(a % -b, 20 % -7); BOOST_CHECK_EQUAL(-a % 7, -20 % 7); BOOST_CHECK_EQUAL(-a % -7, -20 % -7); BOOST_CHECK_EQUAL(a % -7, 20 % -7); BOOST_CHECK_EQUAL(-a % 7u, -20 % 7); BOOST_CHECK_EQUAL(-a % a, 0); BOOST_CHECK_EQUAL(-a % 5, 0); BOOST_CHECK_EQUAL(-a % -5, 0); BOOST_CHECK_EQUAL(a % -5, 0); b = -b; BOOST_CHECK_EQUAL(a % b, 20 % -7); a = -a; BOOST_CHECK_EQUAL(a % b, -20 % -7); BOOST_CHECK_EQUAL(a % -7, -20 % -7); b = 7; BOOST_CHECK_EQUAL(a % b, -20 % 7); BOOST_CHECK_EQUAL(a % 7, -20 % 7); BOOST_CHECK_EQUAL(a % 7u, -20 % 7); a = 20; a %= b; BOOST_CHECK_EQUAL(a, 20 % 7); a = -20; a %= b; BOOST_CHECK_EQUAL(a, -20 % 7); a = 20; a %= -b; BOOST_CHECK_EQUAL(a, 20 % -7); a = -20; a %= -b; BOOST_CHECK_EQUAL(a, -20 % -7); a = 5; a %= b - a; BOOST_CHECK_EQUAL(a, 5 % (7 - 5)); a = -20; a %= 7; BOOST_CHECK_EQUAL(a, -20 % 7); a = 20; a %= -7; BOOST_CHECK_EQUAL(a, 20 % -7); a = -20; a %= -7; BOOST_CHECK_EQUAL(a, -20 % -7); #ifndef BOOST_NO_LONG_LONG a = -20; a %= 7uLL; BOOST_CHECK_EQUAL(a, -20 % 7); a = 20; a %= -7LL; BOOST_CHECK_EQUAL(a, 20 % -7); a = -20; a %= -7LL; BOOST_CHECK_EQUAL(a, -20 % -7); #endif a = 400; b = 45; #ifndef BOOST_MP_STANDALONE BOOST_CHECK_EQUAL(gcd(a, -45), boost::integer::gcd(400, 45)); BOOST_CHECK_EQUAL(lcm(a, -45), boost::integer::lcm(400, 45)); BOOST_CHECK_EQUAL(gcd(-400, b), boost::integer::gcd(400, 45)); BOOST_CHECK_EQUAL(lcm(-400, b), boost::integer::lcm(400, 45)); #elif (defined(__cpp_lib_gcd_lcm) && (__cpp_lib_gcd_lcm >= 201606L)) BOOST_CHECK_EQUAL(gcd(a, -45), std::gcd(400, 45)); BOOST_CHECK_EQUAL(lcm(a, -45), std::lcm(400, 45)); BOOST_CHECK_EQUAL(gcd(-400, b), std::gcd(400, 45)); BOOST_CHECK_EQUAL(lcm(-400, b), std::lcm(400, 45)); #endif a = -20; BOOST_CHECK_EQUAL(abs(a), 20); BOOST_CHECK_EQUAL(abs(-a), 20); BOOST_CHECK_EQUAL(abs(+a), 20); a = 20; BOOST_CHECK_EQUAL(abs(a), 20); BOOST_CHECK_EQUAL(abs(-a), 20); BOOST_CHECK_EQUAL(abs(+a), 20); a = -400; b = 45; #ifndef BOOST_MP_STANDALONE BOOST_CHECK_EQUAL(gcd(a, b), boost::integer::gcd(-400, 45)); BOOST_CHECK_EQUAL(lcm(a, b), boost::integer::lcm(-400, 45)); BOOST_CHECK_EQUAL(gcd(a, 45), boost::integer::gcd(-400, 45)); BOOST_CHECK_EQUAL(lcm(a, 45), boost::integer::lcm(-400, 45)); BOOST_CHECK_EQUAL(gcd(-400, b), boost::integer::gcd(-400, 45)); BOOST_CHECK_EQUAL(lcm(-400, b), boost::integer::lcm(-400, 45)); #elif (defined(__cpp_lib_gcd_lcm) && (__cpp_lib_gcd_lcm >= 201606L)) BOOST_CHECK_EQUAL(gcd(a, b), std::gcd(-400, 45)); BOOST_CHECK_EQUAL(lcm(a, b), std::lcm(-400, 45)); BOOST_CHECK_EQUAL(gcd(a, 45), std::gcd(-400, 45)); BOOST_CHECK_EQUAL(lcm(a, 45), std::lcm(-400, 45)); BOOST_CHECK_EQUAL(gcd(-400, b), std::gcd(-400, 45)); BOOST_CHECK_EQUAL(lcm(-400, b), std::lcm(-400, 45)); #endif Real r; divide_qr(a, b, c, r); BOOST_CHECK_EQUAL(c, a / b); BOOST_CHECK_EQUAL(r, a % b); BOOST_CHECK_EQUAL(integer_modulus(a, 57), abs(a % 57)); b = -57; divide_qr(a, b, c, r); BOOST_CHECK_EQUAL(c, a / b); BOOST_CHECK_EQUAL(r, a % b); BOOST_CHECK_EQUAL(integer_modulus(a, -57), abs(a % -57)); a = 458; divide_qr(a, b, c, r); BOOST_CHECK_EQUAL(c, a / b); BOOST_CHECK_EQUAL(r, a % b); BOOST_CHECK_EQUAL(integer_modulus(a, -57), abs(a % -57)); #ifndef TEST_CHECKED_INT if (is_checked_cpp_int::value) { a = -1; #if 0//ndef BOOST_NO_EXCEPTIONS BOOST_CHECK_THROW(a << 2, std::range_error); BOOST_CHECK_THROW(a >> 2, std::range_error); BOOST_CHECK_THROW(a <<= 2, std::range_error); BOOST_CHECK_THROW(a >>= 2, std::range_error); #endif } else { a = -1; BOOST_CHECK_EQUAL(a << 10, -1024); a = -23; BOOST_CHECK_EQUAL(a << 10, -23552); a = -23456; BOOST_CHECK_EQUAL(a >> 10, -23); a = -3; BOOST_CHECK_EQUAL(a >> 10, -1); } #endif } template void test_signed_integer_ops(const std::integral_constant&) { } template Real negate_if_signed(Real r, const std::integral_constant&) { return -r; } template Real negate_if_signed(Real r, const std::integral_constant&) { return r; } template void test_integer_overflow() { BOOST_IF_CONSTEXPR (std::numeric_limits::digits > std::numeric_limits::digits) { Real m((std::numeric_limits::max)()); Int r; ++m; if (is_checked_cpp_int::value) { //BOOST_CHECK_THROW(m.template convert_to(), std::overflow_error); } else if (boost::multiprecision::detail::is_signed::value) { r = m.template convert_to(); BOOST_CHECK_EQUAL(r, (std::numeric_limits::max)()); } else { r = m.template convert_to(); BOOST_CHECK_EQUAL(r, 0); } // Again with much larger value: m = 1u; m <<= (std::min)(std::numeric_limits::digits - 1, 1000); if (is_checked_cpp_int::value) { //BOOST_CHECK_THROW(m.template convert_to(), std::overflow_error); } else if (boost::multiprecision::detail::is_signed::value && boost::multiprecision::detail::is_integral::value) { r = m.template convert_to(); BOOST_CHECK_EQUAL(r, (std::numeric_limits::max)()); } else { r = m.template convert_to(); BOOST_CHECK_EQUAL(r, 0); } BOOST_IF_CONSTEXPR (std::numeric_limits::is_signed && (boost::multiprecision::detail::is_signed::value)) { m = (std::numeric_limits::min)(); --m; if (is_checked_cpp_int::value) { //BOOST_CHECK_THROW(m.template convert_to(), std::overflow_error); } else { r = m.template convert_to(); BOOST_CHECK_EQUAL(r, (std::numeric_limits::min)()); } // Again with much larger value: m = 2u; m = pow(m, (std::min)(std::numeric_limits::digits - 1, 1000)); ++m; m = negate_if_signed(m, std::integral_constant::is_signed>()); if (is_checked_cpp_int::value) { //BOOST_CHECK_THROW(m.template convert_to(), std::overflow_error); } else { r = m.template convert_to(); BOOST_CHECK_EQUAL(r, (std::numeric_limits::min)()); } } else BOOST_IF_CONSTEXPR (std::numeric_limits::is_signed && !boost::multiprecision::detail::is_signed::value) { // signed to unsigned converison with overflow, it's really not clear what should happen here! #if 0 m = (std::numeric_limits::max)(); ++m; m = negate_if_signed(m, std::integral_constant::is_signed>()); //BOOST_CHECK_THROW(m.template convert_to(), std::range_error); // Again with much larger value: m = 2u; m = pow(m, (std::min)(std::numeric_limits::digits - 1, 1000)); m = negate_if_signed(m, std::integral_constant::is_signed>()); //BOOST_CHECK_THROW(m.template convert_to(), std::range_error); #endif } } } template void test_integer_round_trip() { BOOST_IF_CONSTEXPR (std::numeric_limits::digits >= std::numeric_limits::digits) { Real m((std::numeric_limits::max)()); Int r = m.template convert_to(); BOOST_CHECK_EQUAL(m, r); BOOST_IF_CONSTEXPR (std::numeric_limits::is_signed && (std::numeric_limits::digits > std::numeric_limits::digits)) { m = (std::numeric_limits::min)(); r = m.template convert_to(); BOOST_CHECK_EQUAL(m, r); } } test_integer_overflow(); } template void test_integer_ops(const std::integral_constant&) { test_signed_integer_ops(std::integral_constant::is_signed>()); Real a(20); Real b(7); Real c(5); BOOST_CHECK_EQUAL(a % b, 20 % 7); BOOST_CHECK_EQUAL(a % 7, 20 % 7); BOOST_CHECK_EQUAL(a % 7u, 20 % 7); BOOST_CHECK_EQUAL(a % a, 0); BOOST_CHECK_EQUAL(a % c, 0); BOOST_CHECK_EQUAL(a % 5, 0); a = a % (b + 0); BOOST_CHECK_EQUAL(a, 20 % 7); a = 20; c = (a + 2) % (a - 1); BOOST_CHECK_EQUAL(c, 22 % 19); c = 5; a = b % (a - 15); BOOST_CHECK_EQUAL(a, 7 % 5); a = 20; a = 20; a %= 7; BOOST_CHECK_EQUAL(a, 20 % 7); #ifndef BOOST_NO_LONG_LONG a = 20; a %= 7uLL; BOOST_CHECK_EQUAL(a, 20 % 7); #endif a = 20; ++a; BOOST_CHECK_EQUAL(a, 21); --a; BOOST_CHECK_EQUAL(a, 20); BOOST_CHECK_EQUAL(a++, 20); BOOST_CHECK_EQUAL(a, 21); BOOST_CHECK_EQUAL(a--, 21); BOOST_CHECK_EQUAL(a, 20); a = 2000; a <<= 20; BOOST_CHECK_EQUAL(a, 2000L << 20); a >>= 20; BOOST_CHECK_EQUAL(a, 2000); a <<= 20u; BOOST_CHECK_EQUAL(a, 2000L << 20); a >>= 20u; BOOST_CHECK_EQUAL(a, 2000); #if 0//ndef BOOST_NO_EXCEPTIONS BOOST_CHECK_THROW(a <<= -20, std::out_of_range); BOOST_CHECK_THROW(a >>= -20, std::out_of_range); BOOST_CHECK_THROW(Real(a << -20), std::out_of_range); BOOST_CHECK_THROW(Real(a >> -20), std::out_of_range); #endif #ifndef BOOST_NO_LONG_LONG if (sizeof(long long) > sizeof(std::size_t)) { // extreme values should trigger an exception: #if 0//ndef BOOST_NO_EXCEPTIONS BOOST_CHECK_THROW(a >>= (1uLL << (sizeof(long long) * CHAR_BIT - 2)), std::out_of_range); BOOST_CHECK_THROW(a <<= (1uLL << (sizeof(long long) * CHAR_BIT - 2)), std::out_of_range); BOOST_CHECK_THROW(a >>= -(1LL << (sizeof(long long) * CHAR_BIT - 2)), std::out_of_range); BOOST_CHECK_THROW(a <<= -(1LL << (sizeof(long long) * CHAR_BIT - 2)), std::out_of_range); BOOST_CHECK_THROW(a >>= (1LL << (sizeof(long long) * CHAR_BIT - 2)), std::out_of_range); BOOST_CHECK_THROW(a <<= (1LL << (sizeof(long long) * CHAR_BIT - 2)), std::out_of_range); #endif // Unless they fit within range: a = 2000L; a <<= 20uLL; BOOST_CHECK_EQUAL(a, (2000L << 20)); a = 2000; a <<= 20LL; BOOST_CHECK_EQUAL(a, (2000L << 20)); #if 0//ndef BOOST_NO_EXCEPTIONS BOOST_CHECK_THROW(Real(a >> (1uLL << (sizeof(long long) * CHAR_BIT - 2))), std::out_of_range); BOOST_CHECK_THROW(Real(a <<= (1uLL << (sizeof(long long) * CHAR_BIT - 2))), std::out_of_range); BOOST_CHECK_THROW(Real(a >>= -(1LL << (sizeof(long long) * CHAR_BIT - 2))), std::out_of_range); BOOST_CHECK_THROW(Real(a <<= -(1LL << (sizeof(long long) * CHAR_BIT - 2))), std::out_of_range); BOOST_CHECK_THROW(Real(a >>= (1LL << (sizeof(long long) * CHAR_BIT - 2))), std::out_of_range); BOOST_CHECK_THROW(Real(a <<= (1LL << (sizeof(long long) * CHAR_BIT - 2))), std::out_of_range); #endif // Unless they fit within range: a = 2000L; BOOST_CHECK_EQUAL(Real(a << 20uLL), (2000L << 20)); a = 2000; BOOST_CHECK_EQUAL(Real(a << 20LL), (2000L << 20)); } #endif a = 20; b = a << 20; BOOST_CHECK_EQUAL(b, (20 << 20)); b = a >> 2; BOOST_CHECK_EQUAL(b, (20 >> 2)); b = (a + 2) << 10; BOOST_CHECK_EQUAL(b, (22 << 10)); b = (a + 3) >> 3; BOOST_CHECK_EQUAL(b, (23 >> 3)); // // Bit fiddling: // int i = 1020304; int j = 56789123; int k = 4523187; a = i; b = j; c = a; c &= b; BOOST_CHECK_EQUAL(c, (i & j)); c = a; c &= j; BOOST_CHECK_EQUAL(c, (i & j)); c = a; c &= a + b; BOOST_CHECK_EQUAL(c, (i & (i + j))); BOOST_CHECK_EQUAL((a & b), (i & j)); c = k; a = a & (b + k); BOOST_CHECK_EQUAL(a, (i & (j + k))); a = i; a = (b + k) & a; BOOST_CHECK_EQUAL(a, (i & (j + k))); a = i; c = a & b & k; BOOST_CHECK_EQUAL(c, (i & j & k)); c = a; c &= (c + b); BOOST_CHECK_EQUAL(c, (i & (i + j))); c = a & (b | 1); BOOST_CHECK_EQUAL(c, (i & (j | 1))); test_complement(a, b, c, typename is_twos_complement_integer::type()); a = i; b = j; c = a; c |= b; BOOST_CHECK_EQUAL(c, (i | j)); c = a; c |= j; BOOST_CHECK_EQUAL(c, (i | j)); c = a; c |= a + b; BOOST_CHECK_EQUAL(c, (i | (i + j))); BOOST_CHECK_EQUAL((a | b), (i | j)); c = k; a = a | (b + k); BOOST_CHECK_EQUAL(a, (i | (j + k))); a = i; a = (b + k) | a; BOOST_CHECK_EQUAL(a, (i | (j + k))); a = i; c = a | b | k; BOOST_CHECK_EQUAL(c, (i | j | k)); c = a; c |= (c + b); BOOST_CHECK_EQUAL(c, (i | (i + j))); c = a | (b | 1); BOOST_CHECK_EQUAL(c, (i | (j | 1))); a = i; b = j; c = a; c ^= b; BOOST_CHECK_EQUAL(c, (i ^ j)); c = a; c ^= j; BOOST_CHECK_EQUAL(c, (i ^ j)); c = a; c ^= a + b; BOOST_CHECK_EQUAL(c, (i ^ (i + j))); BOOST_CHECK_EQUAL((a ^ b), (i ^ j)); c = k; a = a ^ (b + k); BOOST_CHECK_EQUAL(a, (i ^ (j + k))); a = i; a = (b + k) ^ a; BOOST_CHECK_EQUAL(a, (i ^ (j + k))); a = i; c = a ^ b ^ k; BOOST_CHECK_EQUAL(c, (i ^ j ^ k)); c = a; c ^= (c + b); BOOST_CHECK_EQUAL(c, (i ^ (i + j))); c = a ^ (b | 1); BOOST_CHECK_EQUAL(c, (i ^ (j | 1))); a = i; b = j; c = k; // // Non-member functions: // a = 400; b = 45; #ifndef BOOST_MP_STANDALONE BOOST_CHECK_EQUAL(gcd(a, b), boost::integer::gcd(400, 45)); BOOST_CHECK_EQUAL(lcm(a, b), boost::integer::lcm(400, 45)); BOOST_CHECK_EQUAL(gcd(a, 45), boost::integer::gcd(400, 45)); BOOST_CHECK_EQUAL(lcm(a, 45), boost::integer::lcm(400, 45)); BOOST_CHECK_EQUAL(gcd(a, 45u), boost::integer::gcd(400, 45)); BOOST_CHECK_EQUAL(lcm(a, 45u), boost::integer::lcm(400, 45)); BOOST_CHECK_EQUAL(gcd(400, b), boost::integer::gcd(400, 45)); BOOST_CHECK_EQUAL(lcm(400, b), boost::integer::lcm(400, 45)); BOOST_CHECK_EQUAL(gcd(400u, b), boost::integer::gcd(400, 45)); BOOST_CHECK_EQUAL(lcm(400u, b), boost::integer::lcm(400, 45)); #elif (defined(__cpp_lib_gcd_lcm) && (__cpp_lib_gcd_lcm >= 201606L)) BOOST_CHECK_EQUAL(gcd(a, b), std::gcd(400, 45)); BOOST_CHECK_EQUAL(lcm(a, b), std::lcm(400, 45)); BOOST_CHECK_EQUAL(gcd(a, 45), std::gcd(400, 45)); BOOST_CHECK_EQUAL(lcm(a, 45), std::lcm(400, 45)); BOOST_CHECK_EQUAL(gcd(a, 45u), std::gcd(400, 45)); BOOST_CHECK_EQUAL(lcm(a, 45u), std::lcm(400, 45)); BOOST_CHECK_EQUAL(gcd(400, b), std::gcd(400, 45)); BOOST_CHECK_EQUAL(lcm(400, b), std::lcm(400, 45)); BOOST_CHECK_EQUAL(gcd(400u, b), std::gcd(400, 45)); BOOST_CHECK_EQUAL(lcm(400u, b), std::lcm(400, 45)); #endif BOOST_IF_CONSTEXPR (std::numeric_limits::is_bounded) { // Fixed precision integer: a = (std::numeric_limits::max)() - 1; b = (std::numeric_limits::max)() / 35; Real div = gcd(a, b); BOOST_CHECK_EQUAL(a % div, 0); BOOST_CHECK_EQUAL(b % div, 0); } // // Conditionals involving 2 arg functions: // test_conditional(Real(gcd(a, b)), gcd(a, b)); Real r; divide_qr(a, b, c, r); BOOST_CHECK_EQUAL(c, a / b); BOOST_CHECK_EQUAL(r, a % b); divide_qr(a + 0, b, c, r); BOOST_CHECK_EQUAL(c, a / b); BOOST_CHECK_EQUAL(r, a % b); divide_qr(a, b + 0, c, r); BOOST_CHECK_EQUAL(c, a / b); BOOST_CHECK_EQUAL(r, a % b); divide_qr(a + 0, b + 0, c, r); BOOST_CHECK_EQUAL(c, a / b); BOOST_CHECK_EQUAL(r, a % b); BOOST_CHECK_EQUAL(integer_modulus(a, 57), a % 57); for (i = 0; i < 20; ++i) { if (std::numeric_limits::is_specialized && (!std::numeric_limits::is_bounded || ((int)i * 17 < std::numeric_limits::digits))) { BOOST_CHECK_EQUAL(lsb(Real(1) << (i * 17)), static_cast(i * 17)); BOOST_CHECK_EQUAL(msb(Real(1) << (i * 17)), static_cast(i * 17)); BOOST_CHECK(bit_test(Real(1) << (i * 17), i * 17)); BOOST_CHECK(!bit_test(Real(1) << (i * 17), i * 17 + 1)); if (i) { BOOST_CHECK(!bit_test(Real(1) << (i * 17), i * 17 - 1)); } Real zero(0); BOOST_CHECK(bit_test(bit_set(zero, i * 17), i * 17)); zero = 0; BOOST_CHECK_EQUAL(bit_flip(zero, i * 17), Real(1) << i * 17); zero = Real(1) << i * 17; BOOST_CHECK_EQUAL(bit_flip(zero, i * 17), 0); zero = Real(1) << i * 17; BOOST_CHECK_EQUAL(bit_unset(zero, i * 17), 0); } } // // pow, powm: // BOOST_CHECK_EQUAL(pow(Real(3), 4u), 81); BOOST_CHECK_EQUAL(pow(Real(3) + Real(0), 4u), 81); BOOST_CHECK_EQUAL(powm(Real(3), Real(4), Real(13)), 81 % 13); BOOST_CHECK_EQUAL(powm(Real(3), Real(4), 13), 81 % 13); BOOST_CHECK_EQUAL(powm(Real(3), Real(4), Real(13) + 0), 81 % 13); BOOST_CHECK_EQUAL(powm(Real(3), Real(4) + 0, Real(13)), 81 % 13); BOOST_CHECK_EQUAL(powm(Real(3), Real(4) + 0, 13), 81 % 13); BOOST_CHECK_EQUAL(powm(Real(3), Real(4) + 0, Real(13) + 0), 81 % 13); BOOST_CHECK_EQUAL(powm(Real(3), 4 + 0, Real(13)), 81 % 13); BOOST_CHECK_EQUAL(powm(Real(3), 4 + 0, 13), 81 % 13); BOOST_CHECK_EQUAL(powm(Real(3), 4 + 0, Real(13) + 0), 81 % 13); BOOST_CHECK_EQUAL(powm(Real(3) + 0, Real(4), Real(13)), 81 % 13); BOOST_CHECK_EQUAL(powm(Real(3) + 0, Real(4), 13), 81 % 13); BOOST_CHECK_EQUAL(powm(Real(3) + 0, Real(4), Real(13) + 0), 81 % 13); BOOST_CHECK_EQUAL(powm(Real(3) + 0, Real(4) + 0, Real(13)), 81 % 13); BOOST_CHECK_EQUAL(powm(Real(3) + 0, Real(4) + 0, 13), 81 % 13); BOOST_CHECK_EQUAL(powm(Real(3) + 0, Real(4) + 0, Real(13) + 0), 81 % 13); BOOST_CHECK_EQUAL(powm(Real(3) + 0, 4 + 0, Real(13)), 81 % 13); BOOST_CHECK_EQUAL(powm(Real(3) + 0, 4 + 0, 13), 81 % 13); BOOST_CHECK_EQUAL(powm(Real(3) + 0, 4 + 0, Real(13) + 0), 81 % 13); // // Conditionals involving 3 arg functions: // test_conditional(Real(powm(Real(3), Real(4), Real(13))), powm(Real(3), Real(4), Real(13))); #if 0 //ndef BOOST_NO_EXCEPTIONS // // Things that are expected errors: // BOOST_CHECK_THROW(Real("3.14"), std::runtime_error); BOOST_CHECK_THROW(Real("3L"), std::runtime_error); BOOST_CHECK_THROW(Real(Real(20) / 0u), std::overflow_error); #endif // // Extra tests added for full coverage: // a = 20; b = 7; c = 20 % b; BOOST_CHECK_EQUAL(c, (20 % 7)); c = 20 % (b + 0); BOOST_CHECK_EQUAL(c, (20 % 7)); c = a & 10; BOOST_CHECK_EQUAL(c, (20 & 10)); c = 10 & a; BOOST_CHECK_EQUAL(c, (20 & 10)); c = (a + 0) & (b + 0); BOOST_CHECK_EQUAL(c, (20 & 7)); c = 10 & (a + 0); BOOST_CHECK_EQUAL(c, (20 & 10)); c = 10 | a; BOOST_CHECK_EQUAL(c, (20 | 10)); c = (a + 0) | (b + 0); BOOST_CHECK(c == (20 | 7)) c = 20 | (b + 0); BOOST_CHECK_EQUAL(c, (20 | 7)); c = a ^ 7; BOOST_CHECK_EQUAL(c, (20 ^ 7)); c = 20 ^ b; BOOST_CHECK_EQUAL(c, (20 ^ 7)); c = (a + 0) ^ (b + 0); BOOST_CHECK_EQUAL(c, (20 ^ 7)); c = 20 ^ (b + 0); BOOST_CHECK_EQUAL(c, (20 ^ 7)); // // RValue ref tests: // c = Real(20) % b; BOOST_CHECK_EQUAL(c, (20 % 7)); c = a % Real(7); BOOST_CHECK_EQUAL(c, (20 % 7)); c = Real(20) % Real(7); BOOST_CHECK_EQUAL(c, (20 % 7)); c = Real(20) % 7; BOOST_CHECK_EQUAL(c, (20 % 7)); c = 20 % Real(7); BOOST_CHECK_EQUAL(c, (20 % 7)); c = Real(20) % (b * 1); BOOST_CHECK_EQUAL(c, (20 % 7)); c = (a * 1 + 0) % Real(7); BOOST_CHECK_EQUAL(c, (20 % 7)); c = Real(20) >> 2; BOOST_CHECK_EQUAL(c, (20 >> 2)); c = Real(20) & b; BOOST_CHECK_EQUAL(c, (20 & 7)); c = a & Real(7); BOOST_CHECK_EQUAL(c, (20 & 7)); c = Real(20) & Real(7); BOOST_CHECK_EQUAL(c, (20 & 7)); c = Real(20) & 7; BOOST_CHECK_EQUAL(c, (20 & 7)); c = 20 & Real(7); BOOST_CHECK_EQUAL(c, (20 & 7)); c = Real(20) & (b * 1 + 0); BOOST_CHECK_EQUAL(c, (20 & 7)); c = (a * 1 + 0) & Real(7); BOOST_CHECK_EQUAL(c, (20 & 7)); c = Real(20) | b; BOOST_CHECK_EQUAL(c, (20 | 7)); c = a | Real(7); BOOST_CHECK_EQUAL(c, (20 | 7)); c = Real(20) | Real(7); BOOST_CHECK_EQUAL(c, (20 | 7)); c = Real(20) | 7; BOOST_CHECK_EQUAL(c, (20 | 7)); c = 20 | Real(7); BOOST_CHECK_EQUAL(c, (20 | 7)); c = Real(20) | (b * 1 + 0); BOOST_CHECK_EQUAL(c, (20 | 7)); c = (a * 1 + 0) | Real(7); BOOST_CHECK_EQUAL(c, (20 | 7)); c = Real(20) ^ b; BOOST_CHECK_EQUAL(c, (20 ^ 7)); c = a ^ Real(7); BOOST_CHECK_EQUAL(c, (20 ^ 7)); c = Real(20) ^ Real(7); BOOST_CHECK_EQUAL(c, (20 ^ 7)); c = Real(20) ^ 7; BOOST_CHECK_EQUAL(c, (20 ^ 7)); c = 20 ^ Real(7); BOOST_CHECK_EQUAL(c, (20 ^ 7)); c = Real(20) ^ (b * 1 + 0); BOOST_CHECK_EQUAL(c, (20 ^ 7)); c = (a * 1 + 0) ^ Real(7); BOOST_CHECK_EQUAL(c, (20 ^ 7)); // // Round tripping of built in integers: // test_integer_round_trip(); test_integer_round_trip(); test_integer_round_trip(); test_integer_round_trip(); test_integer_round_trip(); test_integer_round_trip(); #ifndef BOOST_NO_LONG_LONG test_integer_round_trip(); test_integer_round_trip(); #endif } template void test_float_funcs(const T&) {} template void test_float_funcs(const std::integral_constant&) { if (boost::multiprecision::is_interval_number::value) return; // // Test variable reuse in function calls, see https://svn.boost.org/trac/boost/ticket/8326 // Real a(2), b(10), c, d; a = pow(a, b); BOOST_CHECK_EQUAL(a, 1024); a = 2; b = pow(a, b); BOOST_CHECK_EQUAL(b, 1024); b = 10; a = pow(a, 10); BOOST_CHECK_EQUAL(a, 1024); a = -2; a = abs(a); BOOST_CHECK_EQUAL(a, 2); a = -2; a = fabs(a); BOOST_CHECK_EQUAL(a, 2); a = 2.5; a = floor(a); BOOST_CHECK_EQUAL(a, 2); a = 2.5; a = ceil(a); BOOST_CHECK_EQUAL(a, 3); a = 2.5; a = trunc(a); BOOST_CHECK_EQUAL(a, 2); a = 2.25; a = round(a); BOOST_CHECK_EQUAL(a, 2); a = 2; a = ldexp(a, 1); BOOST_CHECK_EQUAL(a, 4); int i; a = frexp(a, &i); BOOST_CHECK_EQUAL(a, 0.5); Real tol = std::numeric_limits::epsilon() * 3; a = 4; a = sqrt(a); BOOST_CHECK_CLOSE_FRACTION(a, 2, tol); a = 3; a = exp(a); BOOST_CHECK_CLOSE_FRACTION(a, Real(exp(Real(3))), tol); a = 3; a = log(a); BOOST_CHECK_CLOSE_FRACTION(a, Real(log(Real(3))), tol); a = 3; a = log10(a); BOOST_CHECK_CLOSE_FRACTION(a, Real(log10(Real(3))), tol); a = 0.5; a = sin(a); BOOST_CHECK_CLOSE_FRACTION(a, Real(sin(Real(0.5))), tol); a = 0.5; a = cos(a); BOOST_CHECK_CLOSE_FRACTION(a, Real(cos(Real(0.5))), tol); a = 0.5; a = tan(a); BOOST_CHECK_CLOSE_FRACTION(a, Real(tan(Real(0.5))), tol); a = 0.5; a = asin(a); BOOST_CHECK_CLOSE_FRACTION(a, Real(asin(Real(0.5))), tol); a = 0.5; a = acos(a); BOOST_CHECK_CLOSE_FRACTION(a, Real(acos(Real(0.5))), tol); a = 0.5; a = atan(a); BOOST_CHECK_CLOSE_FRACTION(a, Real(atan(Real(0.5))), tol); a = 0.5; a = sinh(a); BOOST_CHECK_CLOSE_FRACTION(a, Real(sinh(Real(0.5))), tol); a = 0.5; a = cosh(a); BOOST_CHECK_CLOSE_FRACTION(a, Real(cosh(Real(0.5))), tol); a = 0.5; a = tanh(a); BOOST_CHECK_CLOSE_FRACTION(a, Real(tanh(Real(0.5))), tol); // fmod, need to check all the sign permutations: a = 4; b = 2; a = fmod(a, b); BOOST_CHECK_CLOSE_FRACTION(a, Real(fmod(Real(4), Real(2))), tol); a = 4; b = fmod(a, b); BOOST_CHECK_CLOSE_FRACTION(b, Real(fmod(Real(4), Real(2))), tol); a = 4; b = 2; a = fmod(-a, b); BOOST_CHECK_CLOSE_FRACTION(a, Real(fmod(-Real(4), Real(2))), tol); a = 4; b = fmod(-a, b); BOOST_CHECK_CLOSE_FRACTION(b, Real(-fmod(Real(4), Real(2))), tol); a = 4; b = 2; a = fmod(a, -b); BOOST_CHECK_CLOSE_FRACTION(a, Real(fmod(Real(4), -Real(2))), tol); a = 4; b = fmod(a, -b); BOOST_CHECK_CLOSE_FRACTION(b, Real(fmod(Real(4), -Real(2))), tol); a = 4; b = 2; a = fmod(-a, -b); BOOST_CHECK_CLOSE_FRACTION(a, Real(fmod(-Real(4), -Real(2))), tol); a = 4; b = fmod(-a, -b); BOOST_CHECK_CLOSE_FRACTION(b, Real(fmod(-Real(4), -Real(2))), tol); // modf: a = 5; a /= 2; b = modf(a, &c); BOOST_CHECK_EQUAL(b + c, a); BOOST_CHECK_EQUAL(b > 0, a > 0); BOOST_CHECK_EQUAL(c > 0, a > 0); a = -a; b = modf(a, &c); BOOST_CHECK_EQUAL(b + c, a); BOOST_CHECK_EQUAL(b > 0, a > 0); BOOST_CHECK_EQUAL(c > 0, a > 0); b = modf(a, &c); c = 0; modf(a, &c); BOOST_CHECK_EQUAL(b + c, a); BOOST_CHECK_EQUAL(b > 0, a > 0); BOOST_CHECK_EQUAL(c > 0, a > 0); a = -a; b = modf(a, &c); c = 0; modf(a, &c); BOOST_CHECK_EQUAL(b + c, a); BOOST_CHECK_EQUAL(b > 0, a > 0); BOOST_CHECK_EQUAL(c > 0, a > 0); BOOST_IF_CONSTEXPR (std::numeric_limits::has_infinity) { a = std::numeric_limits::infinity(); b = modf(a, &c); BOOST_CHECK_EQUAL(a, c); BOOST_CHECK_EQUAL(b, 0); a = -std::numeric_limits::infinity(); b = modf(a, &c); BOOST_CHECK_EQUAL(a, c); BOOST_CHECK_EQUAL(b, 0); } BOOST_IF_CONSTEXPR (std::numeric_limits::has_quiet_NaN) { a = std::numeric_limits::quiet_NaN(); b = modf(a, &c); #ifndef BOOST_MP_STANDALONE BOOST_CHECK((boost::math::isnan)(b)); BOOST_CHECK((boost::math::isnan)(c)); #endif } a = 4; b = 2; a = atan2(a, b); BOOST_CHECK_CLOSE_FRACTION(a, Real(atan2(Real(4), Real(2))), tol); a = 4; b = atan2(a, b); BOOST_CHECK_CLOSE_FRACTION(b, Real(atan2(Real(4), Real(2))), tol); // fma: a = 2; b = 4; c = 6; BOOST_CHECK_EQUAL(fma(a, b, c), 14); BOOST_CHECK_EQUAL(fma(a, 4, c), 14); BOOST_CHECK_EQUAL(fma(a, b, 6), 14); BOOST_CHECK_EQUAL(fma(a, 4, 6), 14); BOOST_CHECK_EQUAL(fma(a + 0, b, c), 14); BOOST_CHECK_EQUAL(fma(a - 0, 4, c), 14); BOOST_CHECK_EQUAL(fma(a * 1, b, 6), 14); BOOST_CHECK_EQUAL(fma(a / 1, 4, 6), 14); BOOST_CHECK_EQUAL(fma(2, b, c), 14); BOOST_CHECK_EQUAL(fma(2, b, 6), 14); BOOST_CHECK_EQUAL(fma(2, b * 1, c), 14); BOOST_CHECK_EQUAL(fma(2, b + 0, 6), 14); BOOST_CHECK_EQUAL(fma(2, 4, c), 14); BOOST_CHECK_EQUAL(fma(2, 4, c + 0), 14); // Default construct, for consistency with native floats, default constructed values are zero: Real zero; BOOST_CHECK_EQUAL(zero, 0); // // Complex number functions on scalars: // a = 40; BOOST_CHECK_EQUAL(Real(arg(a)), 0); BOOST_CHECK_EQUAL(Real(arg(a + 0)), 0); a - 20; BOOST_CHECK_EQUAL(Real(arg(a)), 0); BOOST_CHECK_EQUAL(Real(arg(a - 20)), 0); } template void compare_NaNs(const T& a, const U& b) { BOOST_CHECK_EQUAL(a == b, false); BOOST_CHECK_EQUAL(a != b, true); BOOST_CHECK_EQUAL(a <= b, false); BOOST_CHECK_EQUAL(a >= b, false); BOOST_CHECK_EQUAL(a > b, false); BOOST_CHECK_EQUAL(a < b, false); // // Again where LHS may be an expression template: // BOOST_CHECK_EQUAL(1 * a == b, false); BOOST_CHECK_EQUAL(1 * a != b, true); BOOST_CHECK_EQUAL(1 * a <= b, false); BOOST_CHECK_EQUAL(1 * a >= b, false); BOOST_CHECK_EQUAL(1 * a > b, false); BOOST_CHECK_EQUAL(1 * a < b, false); // // Again where RHS may be an expression template: // BOOST_CHECK_EQUAL(a == b * 1, false); BOOST_CHECK_EQUAL(a != b * 1, true); BOOST_CHECK_EQUAL(a <= b * 1, false); BOOST_CHECK_EQUAL(a >= b * 1, false); BOOST_CHECK_EQUAL(a > b * 1, false); BOOST_CHECK_EQUAL(a < b * 1, false); // // Again where LHS and RHS may be an expression templates: // BOOST_CHECK_EQUAL(1 * a == b * 1, false); BOOST_CHECK_EQUAL(1 * a != b * 1, true); BOOST_CHECK_EQUAL(1 * a <= b * 1, false); BOOST_CHECK_EQUAL(1 * a >= b * 1, false); BOOST_CHECK_EQUAL(1 * a > b * 1, false); BOOST_CHECK_EQUAL(1 * a < b * 1, false); } template void test_float_ops(const T&) {} template void test_float_ops(const std::integral_constant&) { BOOST_CHECK_EQUAL(abs(Real(2)), 2); BOOST_CHECK_EQUAL(abs(Real(-2)), 2); BOOST_CHECK_EQUAL(fabs(Real(2)), 2); BOOST_CHECK_EQUAL(fabs(Real(-2)), 2); BOOST_CHECK_EQUAL(floor(Real(5) / 2), 2); BOOST_CHECK_EQUAL(ceil(Real(5) / 2), 3); BOOST_CHECK_EQUAL(floor(Real(-5) / 2), -3); BOOST_CHECK_EQUAL(ceil(Real(-5) / 2), -2); BOOST_CHECK_EQUAL(trunc(Real(5) / 2), 2); BOOST_CHECK_EQUAL(trunc(Real(-5) / 2), -2); // // ldexp and frexp, these pretty much have to be implemented by each backend: // typedef typename Real::backend_type::exponent_type e_type; BOOST_CHECK_EQUAL(ldexp(Real(2), 5), 64); BOOST_CHECK_EQUAL(ldexp(Real(2), -5), Real(2) / 32); Real v(512); e_type exponent; Real r = frexp(v, &exponent); BOOST_CHECK_EQUAL(r, 0.5); BOOST_CHECK_EQUAL(exponent, 10); BOOST_CHECK_EQUAL(v, 512); v = 1 / v; r = frexp(v, &exponent); BOOST_CHECK_EQUAL(r, 0.5); BOOST_CHECK_EQUAL(exponent, -8); BOOST_CHECK_EQUAL(ldexp(Real(2), e_type(5)), 64); BOOST_CHECK_EQUAL(ldexp(Real(2), e_type(-5)), Real(2) / 32); v = 512; e_type exp2; r = frexp(v, &exp2); BOOST_CHECK_EQUAL(r, 0.5); BOOST_CHECK_EQUAL(exp2, 10); BOOST_CHECK_EQUAL(v, 512); v = 1 / v; r = frexp(v, &exp2); BOOST_CHECK_EQUAL(r, 0.5); BOOST_CHECK_EQUAL(exp2, -8); // // scalbn and logb, these are the same as ldexp and frexp unless the radix is // something other than 2: // BOOST_IF_CONSTEXPR (std::numeric_limits::is_specialized && std::numeric_limits::radix) { BOOST_CHECK_EQUAL(scalbn(Real(2), 5), 2 * pow(double(std::numeric_limits::radix), 5)); BOOST_CHECK_EQUAL(scalbn(Real(2), -5), Real(2) / pow(double(std::numeric_limits::radix), 5)); v = 512; exponent = ilogb(v); r = scalbn(v, -exponent); BOOST_CHECK(r >= 1); BOOST_CHECK(r < std::numeric_limits::radix); BOOST_CHECK_EQUAL(exponent, logb(v)); BOOST_CHECK_EQUAL(v, scalbn(r, exponent)); v = 1 / v; exponent = ilogb(v); r = scalbn(v, -exponent); BOOST_CHECK(r >= 1); BOOST_CHECK(r < std::numeric_limits::radix); BOOST_CHECK_EQUAL(exponent, logb(v)); BOOST_CHECK_EQUAL(v, scalbn(r, exponent)); } // // pow and exponent: // #ifndef BOOST_MP_STANDALONE v = 3.25; r = pow(v, 0); BOOST_CHECK_EQUAL(r, 1); r = pow(v, 1); BOOST_CHECK_EQUAL(r, 3.25); r = pow(v, 2); BOOST_CHECK_EQUAL(r, boost::math::pow<2>(3.25)); r = pow(v, 3); BOOST_CHECK_EQUAL(r, boost::math::pow<3>(3.25)); r = pow(v, 4); BOOST_CHECK_EQUAL(r, boost::math::pow<4>(3.25)); r = pow(v, 5); BOOST_CHECK_EQUAL(r, boost::math::pow<5>(3.25)); r = pow(v, 6); BOOST_CHECK_EQUAL(r, boost::math::pow<6>(3.25)); r = pow(v, 25); BOOST_CHECK_EQUAL(r, boost::math::pow<25>(Real(3.25))); #endif #ifndef BOOST_NO_EXCEPTIONS // // Things that are expected errors: // //BOOST_CHECK_THROW(Real("3.14L"), std::runtime_error); BOOST_IF_CONSTEXPR (std::numeric_limits::is_specialized) { BOOST_IF_CONSTEXPR (std::numeric_limits::has_infinity) { #ifndef BOOST_MP_STANDALONE BOOST_CHECK((boost::math::isinf)(Real(20) / 0u)); #endif } else { //BOOST_CHECK_THROW(r = Real(Real(20) / 0u), std::overflow_error); } } #endif // // Comparisons of NaN's should always fail: // BOOST_IF_CONSTEXPR (std::numeric_limits::has_quiet_NaN) { r = v = std::numeric_limits::quiet_NaN(); compare_NaNs(r, v); v = 0; compare_NaNs(r, v); r.swap(v); compare_NaNs(r, v); // // Conmpare NaN to int: // compare_NaNs(v, 0); compare_NaNs(0, v); // // Compare to floats: // compare_NaNs(v, 0.5); compare_NaNs(0.5, v); BOOST_IF_CONSTEXPR (std::numeric_limits::has_quiet_NaN) { compare_NaNs(r, std::numeric_limits::quiet_NaN()); compare_NaNs(std::numeric_limits::quiet_NaN(), r); } } // // Operations involving NaN's as one argument: // BOOST_IF_CONSTEXPR (std::numeric_limits::has_quiet_NaN) { #ifndef BOOST_MP_STANDALONE v = 20.25; r = std::numeric_limits::quiet_NaN(); BOOST_CHECK((boost::math::isnan)(v + r)); BOOST_CHECK((boost::math::isnan)(r + v)); BOOST_CHECK((boost::math::isnan)(r - v)); BOOST_CHECK((boost::math::isnan)(v - r)); BOOST_CHECK((boost::math::isnan)(r * v)); BOOST_CHECK((boost::math::isnan)(v * r)); BOOST_CHECK((boost::math::isnan)(r / v)); BOOST_CHECK((boost::math::isnan)(v / r)); Real t = v; BOOST_CHECK((boost::math::isnan)(t += r)); t = r; BOOST_CHECK((boost::math::isnan)(t += v)); t = r; BOOST_CHECK((boost::math::isnan)(t -= v)); t = v; BOOST_CHECK((boost::math::isnan)(t -= r)); t = r; BOOST_CHECK((boost::math::isnan)(t *= v)); t = v; BOOST_CHECK((boost::math::isnan)(t *= r)); t = r; BOOST_CHECK((boost::math::isnan)(t /= v)); t = v; BOOST_CHECK((boost::math::isnan)(t /= r)); #endif } // // Operations involving infinities as one argument: // BOOST_IF_CONSTEXPR (std::numeric_limits::has_infinity) { v = 20.25; r = std::numeric_limits::infinity(); #ifndef BOOST_MP_STANDALONE BOOST_CHECK((boost::math::isinf)(v + r)); BOOST_CHECK((boost::math::isinf)(r + v)); BOOST_CHECK((boost::math::isinf)(r - v)); BOOST_CHECK((boost::math::isinf)(v - r)); BOOST_CHECK((boost::math::isinf)(r * v)); BOOST_CHECK((boost::math::isinf)(v * r)); BOOST_CHECK((boost::math::isinf)(r / v)); #endif BOOST_CHECK_LT(v - r, 0); BOOST_CHECK_EQUAL(v / r, 0); #ifndef BOOST_MP_STANDALONE Real t = v; BOOST_CHECK((boost::math::isinf)(t += r)); t = r; BOOST_CHECK((boost::math::isinf)(t += v)); t = r; BOOST_CHECK((boost::math::isinf)(t -= v)); t = v; BOOST_CHECK((boost::math::isinf)(t -= r)); t = v; BOOST_CHECK(t -= r < 0); t = r; BOOST_CHECK((boost::math::isinf)(t *= v)); t = v; BOOST_CHECK((boost::math::isinf)(t *= r)); t = r; BOOST_CHECK((boost::math::isinf)(t /= v)); t = v; BOOST_CHECK((t /= r) == 0); #endif } // // Operations that should produce NaN as a result: // BOOST_IF_CONSTEXPR (std::numeric_limits::has_quiet_NaN) { v = r = 0; Real t = v / r; #ifndef BOOST_MP_STANDALONE BOOST_CHECK((boost::math::isnan)(t)); v /= r; BOOST_CHECK((boost::math::isnan)(v)); t = v / 0; BOOST_CHECK((boost::math::isnan)(v)); #endif BOOST_IF_CONSTEXPR (std::numeric_limits::has_infinity) { #ifndef BOOST_MP_STANDALONE v = 0; r = std::numeric_limits::infinity(); t = v * r; if (!boost::multiprecision::is_interval_number::value) { BOOST_CHECK((boost::math::isnan)(t)); t = r * 0; BOOST_CHECK((boost::math::isnan)(t)); } v = r; t = r / v; BOOST_CHECK((boost::math::isnan)(t)); #endif } } test_float_funcs(std::integral_constant::is_specialized>()); } template struct lexical_cast_target_type { typedef typename std::conditional< boost::multiprecision::detail::is_signed::value && boost::multiprecision::detail::is_integral::value, std::intmax_t, typename std::conditional< boost::multiprecision::detail::is_unsigned::value, std::uintmax_t, T>::type>::type type; }; template void test_negative_mixed_minmax(std::integral_constant const&) { if (!std::numeric_limits::is_bounded || (std::numeric_limits::digits >= std::numeric_limits::digits)) { Real mx1((std::numeric_limits::max)() - 1); ++mx1; Real mx2((std::numeric_limits::max)()); BOOST_CHECK_EQUAL(mx1, mx2); mx1 = (std::numeric_limits::max)() - 1; ++mx1; mx2 = (std::numeric_limits::max)(); BOOST_CHECK_EQUAL(mx1, mx2); if (!std::numeric_limits::is_bounded || (std::numeric_limits::digits > std::numeric_limits::digits)) { Real mx3((std::numeric_limits::min)() + 1); --mx3; Real mx4((std::numeric_limits::min)()); BOOST_CHECK_EQUAL(mx3, mx4); mx3 = (std::numeric_limits::min)() + 1; --mx3; mx4 = (std::numeric_limits::min)(); BOOST_CHECK_EQUAL(mx3, mx4); } } } template void test_negative_mixed_minmax(std::integral_constant const&) { } template void test_negative_mixed_numeric_limits(std::integral_constant const&) { #ifndef BOOST_MP_STANDALONE typedef typename lexical_cast_target_type::type target_type; #if defined(TEST_MPFR) Num tol = 10 * std::numeric_limits::epsilon(); #else Num tol = 0; #endif static const int left_shift = std::numeric_limits::digits - 1; Num n1 = -static_cast(1uLL << ((left_shift < 63) && (left_shift > 0) ? left_shift : 10)); Num n2 = -1; Num n3 = 0; Num n4 = -20; std::ios_base::fmtflags f = std::is_floating_point::value ? std::ios_base::scientific : std::ios_base::fmtflags(0); int digits_to_print = std::is_floating_point::value && std::numeric_limits::is_specialized ? std::numeric_limits::digits10 + 5 : 0; BOOST_IF_CONSTEXPR (std::numeric_limits::digits <= std::numeric_limits::digits) { BOOST_CHECK_CLOSE(n1, checked_lexical_cast(Real(n1).str(digits_to_print, f)), tol); } BOOST_CHECK_CLOSE(n2, checked_lexical_cast(Real(n2).str(digits_to_print, f)), 0); BOOST_CHECK_CLOSE(n3, checked_lexical_cast(Real(n3).str(digits_to_print, f)), 0); BOOST_CHECK_CLOSE(n4, checked_lexical_cast(Real(n4).str(digits_to_print, f)), 0); #endif } template void test_negative_mixed_numeric_limits(std::integral_constant const&) {} template void test_negative_mixed(std::integral_constant const&) { typedef typename std::conditional< std::is_convertible::value, typename std::conditional::value && (sizeof(Num) < sizeof(int)), int, Num>::type, Real>::type cast_type; typedef typename std::conditional< std::is_convertible::value, Num, Real>::type simple_cast_type; std::cout << "Testing mixed arithmetic with type: " << name_of() << " and " << name_of() << std::endl; static const int left_shift = std::numeric_limits::digits - 1; Num n1 = -static_cast(1uLL << ((left_shift < 63) && (left_shift > 0) ? left_shift : 10)); Num n2 = -1; Num n3 = 0; Num n4 = -20; Num n5 = -8; test_comparisons(n1, n2, std::is_convertible()); test_comparisons(n1, n3, std::is_convertible()); test_comparisons(n3, n1, std::is_convertible()); test_comparisons(n2, n1, std::is_convertible()); test_comparisons(n1, n1, std::is_convertible()); test_comparisons(n3, n3, std::is_convertible()); // Default construct: BOOST_CHECK_EQUAL(Real(n1), static_cast(n1)); BOOST_CHECK_EQUAL(Real(n2), static_cast(n2)); BOOST_CHECK_EQUAL(Real(n3), static_cast(n3)); BOOST_CHECK_EQUAL(Real(n4), static_cast(n4)); BOOST_CHECK_EQUAL(static_cast(n1), Real(n1)); BOOST_CHECK_EQUAL(static_cast(n2), Real(n2)); BOOST_CHECK_EQUAL(static_cast(n3), Real(n3)); BOOST_CHECK_EQUAL(static_cast(n4), Real(n4)); BOOST_CHECK_EQUAL(Real(n1).template convert_to(), n1); BOOST_CHECK_EQUAL(Real(n2).template convert_to(), n2); BOOST_CHECK_EQUAL(Real(n3).template convert_to(), n3); BOOST_CHECK_EQUAL(Real(n4).template convert_to(), n4); BOOST_CHECK_EQUAL(static_cast(Real(n1)), n1); BOOST_CHECK_EQUAL(static_cast(Real(n2)), n2); BOOST_CHECK_EQUAL(static_cast(Real(n3)), n3); BOOST_CHECK_EQUAL(static_cast(Real(n4)), n4); // Conversions when source is an expression template: BOOST_CHECK_EQUAL((Real(n1) + 0).template convert_to(), n1); BOOST_CHECK_EQUAL((Real(n2) + 0).template convert_to(), n2); BOOST_CHECK_EQUAL((Real(n3) + 0).template convert_to(), n3); BOOST_CHECK_EQUAL((Real(n4) + 0).template convert_to(), n4); BOOST_CHECK_EQUAL(static_cast((Real(n1) + 0)), n1); BOOST_CHECK_EQUAL(static_cast((Real(n2) + 0)), n2); BOOST_CHECK_EQUAL(static_cast((Real(n3) + 0)), n3); BOOST_CHECK_EQUAL(static_cast((Real(n4) + 0)), n4); test_negative_mixed_numeric_limits(std::integral_constant::is_specialized && std::numeric_limits::is_specialized>()); // Assignment: Real r(0); BOOST_CHECK(r != static_cast(n1)); r = static_cast(n1); BOOST_CHECK_EQUAL(r, static_cast(n1)); r = static_cast(n2); BOOST_CHECK_EQUAL(r, static_cast(n2)); r = static_cast(n3); BOOST_CHECK_EQUAL(r, static_cast(n3)); r = static_cast(n4); BOOST_CHECK_EQUAL(r, static_cast(n4)); // Addition: r = static_cast(n2); BOOST_CHECK_EQUAL(r + static_cast(n4), static_cast(n2 + n4)); BOOST_CHECK_EQUAL(Real(r + static_cast(n4)), static_cast(n2 + n4)); r += static_cast(n4); BOOST_CHECK_EQUAL(r, static_cast(n2 + n4)); // subtraction: r = static_cast(n4); BOOST_CHECK_EQUAL(r - static_cast(n5), static_cast(n4 - n5)); BOOST_CHECK_EQUAL(Real(r - static_cast(n5)), static_cast(n4 - n5)); r -= static_cast(n5); BOOST_CHECK_EQUAL(r, static_cast(n4 - n5)); // Multiplication: r = static_cast(n2); BOOST_CHECK_EQUAL(r * static_cast(n4), static_cast(n2 * n4)); BOOST_CHECK_EQUAL(Real(r * static_cast(n4)), static_cast(n2 * n4)); r *= static_cast(n4); BOOST_CHECK_EQUAL(r, static_cast(n2 * n4)); // Division: r = static_cast(n1); BOOST_CHECK_EQUAL(r / static_cast(n5), static_cast(n1 / n5)); BOOST_CHECK_EQUAL(Real(r / static_cast(n5)), static_cast(n1 / n5)); r /= static_cast(n5); BOOST_CHECK_EQUAL(r, static_cast(n1 / n5)); // // Extra cases for full coverage: // r = Real(n4) + static_cast(n5); BOOST_CHECK_EQUAL(r, static_cast(n4 + n5)); r = static_cast(n4) + Real(n5); BOOST_CHECK_EQUAL(r, static_cast(n4 + n5)); r = Real(n4) - static_cast(n5); BOOST_CHECK_EQUAL(r, static_cast(n4 - n5)); r = static_cast(n4) - Real(n5); BOOST_CHECK_EQUAL(r, static_cast(n4 - n5)); r = static_cast(n4) * Real(n5); BOOST_CHECK_EQUAL(r, static_cast(n4 * n5)); r = static_cast(Num(4) * n4) / Real(4); BOOST_CHECK_EQUAL(r, static_cast(n4)); Real a, b, c; a = 20; b = 30; c = -a + b; BOOST_CHECK_EQUAL(c, 10); c = b + -a; BOOST_CHECK_EQUAL(c, 10); n4 = 30; c = -a + static_cast(n4); BOOST_CHECK_EQUAL(c, 10); c = static_cast(n4) + -a; BOOST_CHECK_EQUAL(c, 10); c = -a + -b; BOOST_CHECK_EQUAL(c, -50); n4 = 4; c = -(a + b) + static_cast(n4); BOOST_CHECK_EQUAL(c, -50 + 4); n4 = 50; c = (a + b) - static_cast(n4); BOOST_CHECK_EQUAL(c, 0); c = (a + b) - static_cast(n4); BOOST_CHECK_EQUAL(c, 0); c = a - -(b + static_cast(n4)); BOOST_CHECK_EQUAL(c, 20 - -(30 + 50)); c = -(b + static_cast(n4)) - a; BOOST_CHECK_EQUAL(c, -(30 + 50) - 20); c = a - -b; BOOST_CHECK_EQUAL(c, 50); c = -a - b; BOOST_CHECK_EQUAL(c, -50); c = -a - static_cast(n4); BOOST_CHECK_EQUAL(c, -20 - 50); c = static_cast(n4) - -a; BOOST_CHECK_EQUAL(c, 50 + 20); c = -(a + b) - Real(n4); BOOST_CHECK_EQUAL(c, -(20 + 30) - 50); c = static_cast(n4) - (a + b); BOOST_CHECK_EQUAL(c, 0); c = (a + b) * static_cast(n4); BOOST_CHECK_EQUAL(c, 50 * 50); c = static_cast(n4) * (a + b); BOOST_CHECK_EQUAL(c, 50 * 50); c = a * -(b + static_cast(n4)); BOOST_CHECK_EQUAL(c, 20 * -(30 + 50)); c = -(b + static_cast(n4)) * a; BOOST_CHECK_EQUAL(c, 20 * -(30 + 50)); c = a * -b; BOOST_CHECK_EQUAL(c, 20 * -30); c = -a * b; BOOST_CHECK_EQUAL(c, 20 * -30); c = -a * static_cast(n4); BOOST_CHECK_EQUAL(c, -20 * 50); c = static_cast(n4) * -a; BOOST_CHECK_EQUAL(c, -20 * 50); c = -(a + b) + a; BOOST_CHECK(-50 + 20); c = static_cast(n4) - (a + b); BOOST_CHECK_EQUAL(c, 0); Real d = 10; c = (a + b) / d; BOOST_CHECK_EQUAL(c, 5); c = (a + b) / (d + 0); BOOST_CHECK_EQUAL(c, 5); c = (a + b) / static_cast(n4); BOOST_CHECK_EQUAL(c, 1); c = static_cast(n4) / (a + b); BOOST_CHECK_EQUAL(c, 1); d = 50; c = d / -(a + b); BOOST_CHECK_EQUAL(c, -1); c = -(a + b) / d; BOOST_CHECK_EQUAL(c, -1); d = 2; c = a / -d; BOOST_CHECK_EQUAL(c, 20 / -2); c = -a / d; BOOST_CHECK_EQUAL(c, 20 / -2); d = 50; c = -d / static_cast(n4); BOOST_CHECK_EQUAL(c, -1); c = static_cast(n4) / -d; BOOST_CHECK_EQUAL(c, -1); c = static_cast(n4) + a; BOOST_CHECK_EQUAL(c, 70); c = static_cast(n4) - a; BOOST_CHECK_EQUAL(c, 30); c = static_cast(n4) * a; BOOST_CHECK_EQUAL(c, 50 * 20); n1 = -2; n2 = -3; n3 = -4; a = static_cast(n1); b = static_cast(n2); c = static_cast(n3); d = a + b * c; BOOST_CHECK_EQUAL(d, -2 + -3 * -4); d = static_cast(n1) + b * c; BOOST_CHECK_EQUAL(d, -2 + -3 * -4); d = a + static_cast(n2) * c; BOOST_CHECK_EQUAL(d, -2 + -3 * -4); d = a + b * static_cast(n3); BOOST_CHECK_EQUAL(d, -2 + -3 * -4); d = static_cast(n1) + static_cast(n2) * c; BOOST_CHECK_EQUAL(d, -2 + -3 * -4); d = static_cast(n1) + b * static_cast(n3); BOOST_CHECK_EQUAL(d, -2 + -3 * -4); a += static_cast(n2) * c; BOOST_CHECK_EQUAL(a, -2 + -3 * -4); a = static_cast(n1); a += b * static_cast(n3); BOOST_CHECK_EQUAL(a, -2 + -3 * -4); a = static_cast(n1); d = b * c + a; BOOST_CHECK_EQUAL(d, -2 + -3 * -4); d = b * c + static_cast(n1); BOOST_CHECK_EQUAL(d, -2 + -3 * -4); d = static_cast(n2) * c + a; BOOST_CHECK_EQUAL(d, -2 + -3 * -4); d = b * static_cast(n3) + a; BOOST_CHECK_EQUAL(d, -2 + -3 * -4); d = static_cast(n2) * c + static_cast(n1); BOOST_CHECK_EQUAL(d, -2 + -3 * -4); d = b * static_cast(n3) + static_cast(n1); BOOST_CHECK_EQUAL(d, -2 + -3 * -4); a = -20; d = a - b * c; BOOST_CHECK_EQUAL(d, -20 - -3 * -4); n1 = -20; d = static_cast(n1) - b * c; BOOST_CHECK_EQUAL(d, -20 - -3 * -4); d = a - static_cast(n2) * c; BOOST_CHECK_EQUAL(d, -20 - -3 * -4); d = a - b * static_cast(n3); BOOST_CHECK_EQUAL(d, -20 - -3 * -4); d = static_cast(n1) - static_cast(n2) * c; BOOST_CHECK_EQUAL(d, -20 - -3 * -4); d = static_cast(n1) - b * static_cast(n3); BOOST_CHECK_EQUAL(d, -20 - -3 * -4); a -= static_cast(n2) * c; BOOST_CHECK_EQUAL(a, -20 - -3 * -4); a = static_cast(n1); a -= b * static_cast(n3); BOOST_CHECK_EQUAL(a, -20 - -3 * -4); a = -2; d = b * c - a; BOOST_CHECK_EQUAL(d, -3 * -4 - -2); n1 = -2; d = b * c - static_cast(n1); BOOST_CHECK_EQUAL(d, -3 * -4 - -2); d = static_cast(n2) * c - a; BOOST_CHECK_EQUAL(d, -3 * -4 - -2); d = b * static_cast(n3) - a; BOOST_CHECK_EQUAL(d, -3 * -4 - -2); d = static_cast(n2) * c - static_cast(n1); BOOST_CHECK_EQUAL(d, -3 * -4 - -2); d = b * static_cast(n3) - static_cast(n1); BOOST_CHECK_EQUAL(d, -3 * -4 - -2); // // Conversion from min and max values: // test_negative_mixed_minmax(std::integral_constant::is_integer && std::numeric_limits::is_integer > ()); // // RValue ref overloads: // a = 2; n1 = 3; d = -a + static_cast(n1); BOOST_CHECK_EQUAL(d, 1); d = static_cast(n1) + -a; BOOST_CHECK_EQUAL(d, 1); d = -a - static_cast(n1); BOOST_CHECK_EQUAL(d, -5); d = static_cast(n1) - -a; BOOST_CHECK_EQUAL(d, 5); d = -a * static_cast(n1); BOOST_CHECK_EQUAL(d, -6); d = static_cast(n1) * -a; BOOST_CHECK_EQUAL(d, -6); n1 = 4; d = -static_cast(n1) / a; BOOST_CHECK_EQUAL(d, -2); d = static_cast(n1) / -a; BOOST_CHECK_EQUAL(d, -2); } template void test_negative_mixed(std::integral_constant const&) { } template void test_mixed(const std::integral_constant&) { } template bool check_is_nan(const Real& val, const std::integral_constant&) { #ifndef BOOST_MP_STANDALONE return (boost::math::isnan)(val); #else static_cast(val); return true; // Avoids warnings. This functionality is never used in standalone mode #endif } template bool check_is_nan(const Real&, const std::integral_constant&) { return false; } template Real negate_value(const Real& val, const std::integral_constant&) { return -val; } template Real negate_value(const Real& val, const std::integral_constant&) { return val; } template void test_mixed_numeric_limits(const std::integral_constant&) { #ifndef BOOST_MP_STANDALONE typedef typename lexical_cast_target_type::type target_type; #if defined(TEST_MPFR) Num tol = 10 * std::numeric_limits::epsilon(); #else Num tol = 0; #endif Real d; BOOST_IF_CONSTEXPR (std::numeric_limits::has_infinity && std::numeric_limits::has_infinity) { d = static_cast(std::numeric_limits::infinity()); BOOST_CHECK_GT(d, (std::numeric_limits::max)()); d = static_cast(negate_value(std::numeric_limits::infinity(), std::integral_constant::is_signed>())); BOOST_CHECK_LT(d, negate_value((std::numeric_limits::max)(), std::integral_constant::is_signed>())); } BOOST_IF_CONSTEXPR (std::numeric_limits::has_quiet_NaN && std::numeric_limits::has_quiet_NaN) { #ifndef BOOST_MP_STANDALONE d = static_cast(std::numeric_limits::quiet_NaN()); BOOST_CHECK(check_is_nan(d, std::integral_constant::has_quiet_NaN>())); d = static_cast(negate_value(std::numeric_limits::quiet_NaN(), std::integral_constant::is_signed>())); BOOST_CHECK(check_is_nan(d, std::integral_constant::has_quiet_NaN>())); #endif } static const int left_shift = std::numeric_limits::digits - 1; Num n1 = static_cast(1uLL << ((left_shift < 63) && (left_shift > 0) ? left_shift : 10)); Num n2 = 1; Num n3 = 0; Num n4 = 20; std::ios_base::fmtflags f = std::is_floating_point::value ? std::ios_base::scientific : std::ios_base::fmtflags(0); int digits_to_print = std::is_floating_point::value && std::numeric_limits::is_specialized ? std::numeric_limits::digits10 + 5 : 0; BOOST_IF_CONSTEXPR (std::numeric_limits::digits <= std::numeric_limits::digits) { BOOST_CHECK_CLOSE(n1, checked_lexical_cast(Real(n1).str(digits_to_print, f)), tol); } BOOST_CHECK_CLOSE(n2, checked_lexical_cast(Real(n2).str(digits_to_print, f)), 0); BOOST_CHECK_CLOSE(n3, checked_lexical_cast(Real(n3).str(digits_to_print, f)), 0); BOOST_CHECK_CLOSE(n4, checked_lexical_cast(Real(n4).str(digits_to_print, f)), 0); #endif // BOOST_MP_STANDALONE } template void test_mixed_numeric_limits(const std::integral_constant&) { } template struct is_definitely_unsigned_int : public std::integral_constant::is_specialized && !std::numeric_limits::is_signed> {}; #ifdef BOOST_HAS_INT128 #if (defined(__GNUC__) && !defined(__clang__)) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wpedantic" #endif template <> struct is_definitely_unsigned_int : public std::true_type {}; #if (defined(__GNUC__) && !defined(__clang__)) #pragma GCC diagnostic pop #endif #endif template void test_mixed_rational(const std::true_type&) { Real rat(2, 3); Num zero(0); BOOST_CHECK_EQUAL(rat * zero, zero); rat *= zero; BOOST_CHECK_EQUAL(rat, zero); rat = Real(2, 3); #ifndef BOOST_NO_CXX17_IF_CONSTEXPR BOOST_IF_CONSTEXPR(std::is_floating_point::value) { Real rat2; Num f = 0.5f; rat2 = rat * f; BOOST_CHECK_EQUAL(rat2, rat * Real(1, 2)); rat2 = f * rat; BOOST_CHECK_EQUAL(rat2, rat * Real(1, 2)); rat2 = rat / f; BOOST_CHECK_EQUAL(rat2, rat / Real(1, 2)); rat2 = f / rat; BOOST_CHECK_EQUAL(rat2, Real(1, 2) / rat); rat2 = rat + f; BOOST_CHECK_EQUAL(rat2, rat + Real(1, 2)); rat2 = f + rat; BOOST_CHECK_EQUAL(rat2, rat + Real(1, 2)); rat2 = rat - f; BOOST_CHECK_EQUAL(rat2, rat - Real(1, 2)); f = 1.5f; rat2 = f - rat; BOOST_CHECK_EQUAL(rat2, Real(3, 2) - rat); } #endif } template void test_mixed_rational(const std::false_type&) { } template void test_mixed(const std::integral_constant&) { typedef typename std::conditional< std::is_convertible::value, typename std::conditional::value && (sizeof(Num) < sizeof(int)), int, Num>::type, Real>::type cast_type; typedef typename std::conditional< std::is_convertible::value, Num, Real>::type simple_cast_type; BOOST_IF_CONSTEXPR (std::numeric_limits::is_specialized && std::numeric_limits::is_bounded && std::numeric_limits::digits < std::numeric_limits::digits) return; std::cout << "Testing mixed arithmetic with type: " << name_of() << " and " << name_of() << std::endl; static const int left_shift = std::numeric_limits::digits - 1; Num n1 = static_cast(1uLL << ((left_shift < 63) && (left_shift > 0) ? left_shift : 10)); Num n2 = 1; Num n3 = 0; Num n4 = 20; Num n5 = 8; test_comparisons(n1, n2, std::is_convertible()); test_comparisons(n1, n3, std::is_convertible()); test_comparisons(n1, n1, std::is_convertible()); test_comparisons(n3, n1, std::is_convertible()); test_comparisons(n2, n1, std::is_convertible()); test_comparisons(n3, n3, std::is_convertible()); // Default construct: BOOST_CHECK_EQUAL(Real(n1), static_cast(n1)); BOOST_CHECK_EQUAL(Real(n2), static_cast(n2)); BOOST_CHECK_EQUAL(Real(n3), static_cast(n3)); BOOST_CHECK_EQUAL(Real(n4), static_cast(n4)); BOOST_CHECK_EQUAL(Real(n1).template convert_to(), n1); BOOST_CHECK_EQUAL(Real(n2).template convert_to(), n2); BOOST_CHECK_EQUAL(Real(n3).template convert_to(), n3); BOOST_CHECK_EQUAL(Real(n4).template convert_to(), n4); BOOST_CHECK_EQUAL(static_cast(Real(n1)), n1); BOOST_CHECK_EQUAL(static_cast(Real(n2)), n2); BOOST_CHECK_EQUAL(static_cast(Real(n3)), n3); BOOST_CHECK_EQUAL(static_cast(Real(n4)), n4); // Again with expression templates: BOOST_CHECK_EQUAL((Real(n1) + 0).template convert_to(), n1); BOOST_CHECK_EQUAL((Real(n2) + 0).template convert_to(), n2); BOOST_CHECK_EQUAL((Real(n3) + 0).template convert_to(), n3); BOOST_CHECK_EQUAL((Real(n4) + 0).template convert_to(), n4); BOOST_CHECK_EQUAL(static_cast(Real(n1) + 0), n1); BOOST_CHECK_EQUAL(static_cast(Real(n2) + 0), n2); BOOST_CHECK_EQUAL(static_cast(Real(n3) + 0), n3); BOOST_CHECK_EQUAL(static_cast(Real(n4) + 0), n4); BOOST_CHECK_EQUAL(static_cast(n1), Real(n1)); BOOST_CHECK_EQUAL(static_cast(n2), Real(n2)); BOOST_CHECK_EQUAL(static_cast(n3), Real(n3)); BOOST_CHECK_EQUAL(static_cast(n4), Real(n4)); // Assignment: Real r(0); BOOST_CHECK(r != static_cast(n1)); r = static_cast(n1); BOOST_CHECK_EQUAL(r, static_cast(n1)); r = static_cast(n2); BOOST_CHECK_EQUAL(r, static_cast(n2)); r = static_cast(n3); BOOST_CHECK_EQUAL(r, static_cast(n3)); r = static_cast(n4); BOOST_CHECK_EQUAL(r, static_cast(n4)); // Addition: r = static_cast(n2); BOOST_CHECK_EQUAL(r + static_cast(n4), static_cast(n2 + n4)); BOOST_CHECK_EQUAL(Real(r + static_cast(n4)), static_cast(n2 + n4)); r += static_cast(n4); BOOST_CHECK_EQUAL(r, static_cast(n2 + n4)); // subtraction: r = static_cast(n4); BOOST_CHECK_EQUAL(r - static_cast(n5), static_cast(n4 - n5)); BOOST_CHECK_EQUAL(Real(r - static_cast(n5)), static_cast(n4 - n5)); r -= static_cast(n5); BOOST_CHECK_EQUAL(r, static_cast(n4 - n5)); // Multiplication: r = static_cast(n2); BOOST_CHECK_EQUAL(r * static_cast(n4), static_cast(n2 * n4)); BOOST_CHECK_EQUAL(Real(r * static_cast(n4)), static_cast(n2 * n4)); r *= static_cast(n4); BOOST_CHECK_EQUAL(r, static_cast(n2 * n4)); // Division: r = static_cast(n1); BOOST_CHECK_EQUAL(r / static_cast(n5), static_cast(n1 / n5)); BOOST_CHECK_EQUAL(Real(r / static_cast(n5)), static_cast(n1 / n5)); r /= static_cast(n5); BOOST_CHECK_EQUAL(r, static_cast(n1 / n5)); // // special cases for full coverage: // r = static_cast(n5) + Real(n4); BOOST_CHECK_EQUAL(r, static_cast(n4 + n5)); r = static_cast(n4) - Real(n5); BOOST_CHECK_EQUAL(r, static_cast(n4 - n5)); r = static_cast(n4) * Real(n5); BOOST_CHECK_EQUAL(r, static_cast(n4 * n5)); r = static_cast(Num(4) * n4) / Real(4); BOOST_CHECK_EQUAL(r, static_cast(n4)); typedef std::integral_constant::is_specialized || std::numeric_limits::is_signed) && (!std::numeric_limits::is_specialized || std::numeric_limits::is_signed) && !is_definitely_unsigned_int::value> signed_tag; test_negative_mixed(signed_tag()); n1 = 2; n2 = 3; n3 = 4; Real a(n1), b(n2), c(n3), d; d = a + b * c; BOOST_CHECK_EQUAL(d, 2 + 3 * 4); d = static_cast(n1) + b * c; BOOST_CHECK_EQUAL(d, 2 + 3 * 4); d = a + static_cast(n2) * c; BOOST_CHECK_EQUAL(d, 2 + 3 * 4); d = a + b * static_cast(n3); BOOST_CHECK_EQUAL(d, 2 + 3 * 4); d = static_cast(n1) + static_cast(n2) * c; BOOST_CHECK_EQUAL(d, 2 + 3 * 4); d = static_cast(n1) + b * static_cast(n3); BOOST_CHECK_EQUAL(d, 2 + 3 * 4); a += static_cast(n2) * c; BOOST_CHECK_EQUAL(a, 2 + 3 * 4); a = static_cast(n1); a += b * static_cast(n3); BOOST_CHECK_EQUAL(a, 2 + 3 * 4); a = static_cast(n1); d = b * c + a; BOOST_CHECK_EQUAL(d, 2 + 3 * 4); d = b * c + static_cast(n1); BOOST_CHECK_EQUAL(d, 2 + 3 * 4); d = static_cast(n2) * c + a; BOOST_CHECK_EQUAL(d, 2 + 3 * 4); d = b * static_cast(n3) + a; BOOST_CHECK_EQUAL(d, 2 + 3 * 4); d = static_cast(n2) * c + static_cast(n1); BOOST_CHECK_EQUAL(d, 2 + 3 * 4); d = b * static_cast(n3) + static_cast(n1); BOOST_CHECK_EQUAL(d, 2 + 3 * 4); a = 20; d = a - b * c; BOOST_CHECK_EQUAL(d, 20 - 3 * 4); n1 = 20; d = static_cast(n1) - b * c; BOOST_CHECK_EQUAL(d, 20 - 3 * 4); d = a - static_cast(n2) * c; BOOST_CHECK_EQUAL(d, 20 - 3 * 4); d = a - b * static_cast(n3); BOOST_CHECK_EQUAL(d, 20 - 3 * 4); d = static_cast(n1) - static_cast(n2) * c; BOOST_CHECK_EQUAL(d, 20 - 3 * 4); d = static_cast(n1) - b * static_cast(n3); BOOST_CHECK_EQUAL(d, 20 - 3 * 4); a -= static_cast(n2) * c; BOOST_CHECK_EQUAL(a, 20 - 3 * 4); a = static_cast(n1); a -= b * static_cast(n3); BOOST_CHECK_EQUAL(a, 20 - 3 * 4); a = 2; d = b * c - a; BOOST_CHECK_EQUAL(d, 3 * 4 - 2); n1 = 2; d = b * c - static_cast(n1); BOOST_CHECK_EQUAL(d, 3 * 4 - 2); d = static_cast(n2) * c - a; BOOST_CHECK_EQUAL(d, 3 * 4 - 2); d = b * static_cast(n3) - a; BOOST_CHECK_EQUAL(d, 3 * 4 - a); d = static_cast(n2) * c - static_cast(n1); BOOST_CHECK_EQUAL(d, 3 * 4 - 2); d = b * static_cast(n3) - static_cast(n1); BOOST_CHECK_EQUAL(d, 3 * 4 - 2); test_mixed_numeric_limits(std::integral_constant < bool, std::numeric_limits::is_specialized && std::numeric_limits::is_specialized > ()); test_mixed_rational(std::integral_constant::value == boost::multiprecision::number_kind_rational>()); } template typename std::enable_if::value == boost::multiprecision::number_kind_complex>::type test_members(Real) { // // Test sign and zero functions: // Real a = 20; Real b = 30; BOOST_CHECK(!a.is_zero()); a = -20; BOOST_CHECK(!a.is_zero()); a = 0; BOOST_CHECK(a.is_zero()); a = 20; b = 30; a.swap(b); BOOST_CHECK_EQUAL(a, 30); BOOST_CHECK_EQUAL(b, 20); Real c(2, 3); BOOST_CHECK_EQUAL(a.real(), 30); BOOST_CHECK_EQUAL(a.imag(), 0); BOOST_CHECK_EQUAL(c.real(), 2); BOOST_CHECK_EQUAL(c.imag(), 3); // // try some more 2-argument constructors: // { Real d(40.5, 2); BOOST_CHECK_EQUAL(d.real(), 40.5); BOOST_CHECK_EQUAL(d.imag(), 2); } { Real d("40.5", "2"); BOOST_CHECK_EQUAL(d.real(), 40.5); BOOST_CHECK_EQUAL(d.imag(), 2); } { Real d("40.5", std::string("2")); BOOST_CHECK_EQUAL(d.real(), 40.5); BOOST_CHECK_EQUAL(d.imag(), 2); } #ifndef BOOST_NO_CXX17_HDR_STRING_VIEW { std::string sx("40.550"), sy("222"); std::string_view vx(sx.c_str(), 4), vy(sy.c_str(), 1); Real d(vx, vy); BOOST_CHECK_EQUAL(d.real(), 40.5); BOOST_CHECK_EQUAL(d.imag(), 2); } #endif { typename Real::value_type x(40.5), y(2); Real d(x, y); BOOST_CHECK_EQUAL(d.real(), 40.5); BOOST_CHECK_EQUAL(d.imag(), 2); } #ifdef TEST_MPC { typename Real::value_type x(40.5), y(2); Real d(x.backend().data(), y.backend().data()); BOOST_CHECK_EQUAL(d.real(), 40.5); BOOST_CHECK_EQUAL(d.imag(), 2); } #endif { typename Real::value_type x(40.5); Real d(x, 2); BOOST_CHECK_EQUAL(d.real(), 40.5); BOOST_CHECK_EQUAL(d.imag(), 2); } { typename Real::value_type x(40.5); Real d(2, x); BOOST_CHECK_EQUAL(d.imag(), 40.5); BOOST_CHECK_EQUAL(d.real(), 2); } { typename Real::value_type x(real(a) * real(b) + imag(a) * imag(b)), y(imag(a) * real(b) - real(a) * imag(b)); Real d(real(a) * real(b) + imag(a) * imag(b), imag(a) * real(b) - real(a) * imag(b)); Real e(x, y); BOOST_CHECK_EQUAL(d, e); } // // real and imag setters: // c.real(4); BOOST_CHECK_EQUAL(real(c), 4); c.imag(-55); BOOST_CHECK_EQUAL(imag(c), -55); typename Real::value_type z(20); c.real(z); BOOST_CHECK_EQUAL(real(c), 20); c.real(21L); BOOST_CHECK_EQUAL(real(c), 21); c.real(22L); BOOST_CHECK_EQUAL(real(c), 22); c.real(23UL); BOOST_CHECK_EQUAL(real(c), 23); c.real(24U); BOOST_CHECK_EQUAL(real(c), 24); c.real(25.0f); BOOST_CHECK_EQUAL(real(c), 25); c.real(26.0); BOOST_CHECK_EQUAL(real(c), 26); c.real(27.0L); BOOST_CHECK_EQUAL(real(c), 27); #if defined(BOOST_HAS_LONG_LONG) c.real(28LL); BOOST_CHECK_EQUAL(real(c), 28); c.real(29ULL); BOOST_CHECK_EQUAL(real(c), 29); #endif c.imag(z); BOOST_CHECK_EQUAL(imag(c), 20); c.imag(21L); BOOST_CHECK_EQUAL(imag(c), 21); c.imag(22L); BOOST_CHECK_EQUAL(imag(c), 22); c.imag(23UL); BOOST_CHECK_EQUAL(imag(c), 23); c.imag(24U); BOOST_CHECK_EQUAL(imag(c), 24); c.imag(25.0f); BOOST_CHECK_EQUAL(imag(c), 25); c.imag(26.0); BOOST_CHECK_EQUAL(imag(c), 26); c.imag(27.0L); BOOST_CHECK_EQUAL(imag(c), 27); #if defined(BOOST_HAS_LONG_LONG) c.imag(28LL); BOOST_CHECK_EQUAL(imag(c), 28); c.imag(29ULL); BOOST_CHECK_EQUAL(imag(c), 29); #endif c.real(2).imag(3); BOOST_CHECK_EQUAL(real(a), 30); BOOST_CHECK_EQUAL(imag(a), 0); BOOST_CHECK_EQUAL(real(c), 2); BOOST_CHECK_EQUAL(imag(c), 3); BOOST_CHECK_EQUAL(real(a + 0), 30); BOOST_CHECK_EQUAL(imag(a + 0), 0); BOOST_CHECK_EQUAL(real(c + 0), 2); BOOST_CHECK_EQUAL(imag(c + 0), 3); // string construction: a = Real("2"); BOOST_CHECK_EQUAL(real(a), 2); BOOST_CHECK_EQUAL(imag(a), 0); a = Real("(2)"); BOOST_CHECK_EQUAL(real(a), 2); BOOST_CHECK_EQUAL(imag(a), 0); a = Real("(,2)"); BOOST_CHECK_EQUAL(real(a), 0); BOOST_CHECK_EQUAL(imag(a), 2); a = Real("(2,3)"); BOOST_CHECK_EQUAL(real(a), 2); BOOST_CHECK_EQUAL(imag(a), 3); typedef typename boost::multiprecision::component_type::type real_type; real_type r(3); real_type tol = std::numeric_limits::epsilon() * 30; a = r; BOOST_CHECK_EQUAL(real(a), 3); BOOST_CHECK_EQUAL(imag(a), 0); a += r; BOOST_CHECK_EQUAL(real(a), 6); BOOST_CHECK_EQUAL(imag(a), 0); a *= r; BOOST_CHECK_EQUAL(real(a), 18); BOOST_CHECK_EQUAL(imag(a), 0); a = a / r; BOOST_CHECK_EQUAL(real(a), 6); BOOST_CHECK_EQUAL(imag(a), 0); a = a - r; BOOST_CHECK_EQUAL(real(a), 3); BOOST_CHECK_EQUAL(imag(a), 0); a = r + a; BOOST_CHECK_EQUAL(real(a), 6); BOOST_CHECK_EQUAL(imag(a), 0); r = abs(c); BOOST_CHECK_CLOSE_FRACTION(real_type("3.60555127546398929311922126747049594625129657384524621271045305622716694829301044520461908201849071767351418202406"), r, tol); r = arg(c); BOOST_CHECK_CLOSE_FRACTION(real_type("0.98279372324732906798571061101466601449687745363162855676142508831798807154979603538970653437281731110816513970201"), r, tol); r = norm(c); BOOST_CHECK_CLOSE_FRACTION(real_type(13), r, tol); a = conj(c); BOOST_CHECK_EQUAL(real(a), 2); BOOST_CHECK_EQUAL(imag(a), -3); a = proj(c); BOOST_CHECK_EQUAL(real(a), 2); BOOST_CHECK_EQUAL(imag(a), 3); a = polar(real_type(3), real_type(-10)); BOOST_CHECK_CLOSE_FRACTION(real_type("-2.517214587229357356776591843472194503559790495399505640507861193146377760598812305202801138281266416782353163216"), real(a), tol); BOOST_CHECK_CLOSE_FRACTION(real_type("1.63206333266810944021424298555413184505092903874867167472255203785027162892148027712122702168494964847488147271478"), imag(a), tol); a = polar(real_type(3) + 0, real_type(-10)); BOOST_CHECK_CLOSE_FRACTION(real_type("-2.517214587229357356776591843472194503559790495399505640507861193146377760598812305202801138281266416782353163216"), real(a), tol); BOOST_CHECK_CLOSE_FRACTION(real_type("1.63206333266810944021424298555413184505092903874867167472255203785027162892148027712122702168494964847488147271478"), imag(a), tol); a = polar(real_type(3), real_type(-10) + 0); BOOST_CHECK_CLOSE_FRACTION(real_type("-2.517214587229357356776591843472194503559790495399505640507861193146377760598812305202801138281266416782353163216"), real(a), tol); BOOST_CHECK_CLOSE_FRACTION(real_type("1.63206333266810944021424298555413184505092903874867167472255203785027162892148027712122702168494964847488147271478"), imag(a), tol); a = polar(real_type(3) + 0, real_type(-10) + 0); BOOST_CHECK_CLOSE_FRACTION(real_type("-2.517214587229357356776591843472194503559790495399505640507861193146377760598812305202801138281266416782353163216"), real(a), tol); BOOST_CHECK_CLOSE_FRACTION(real_type("1.63206333266810944021424298555413184505092903874867167472255203785027162892148027712122702168494964847488147271478"), imag(a), tol); a = polar(3, real_type(-10)); BOOST_CHECK_CLOSE_FRACTION(real_type("-2.517214587229357356776591843472194503559790495399505640507861193146377760598812305202801138281266416782353163216"), real(a), tol); BOOST_CHECK_CLOSE_FRACTION(real_type("1.63206333266810944021424298555413184505092903874867167472255203785027162892148027712122702168494964847488147271478"), imag(a), tol); a = polar(3.0, real_type(-10) + 0); BOOST_CHECK_CLOSE_FRACTION(real_type("-2.517214587229357356776591843472194503559790495399505640507861193146377760598812305202801138281266416782353163216"), real(a), tol); BOOST_CHECK_CLOSE_FRACTION(real_type("1.63206333266810944021424298555413184505092903874867167472255203785027162892148027712122702168494964847488147271478"), imag(a), tol); a = polar(real_type(3)); BOOST_CHECK_EQUAL(3, real(a)); BOOST_CHECK_EQUAL(0, imag(a)); a = polar(real_type(3) + 0); BOOST_CHECK_EQUAL(3, real(a)); BOOST_CHECK_EQUAL(0, imag(a)); r = abs(c + 0); BOOST_CHECK_CLOSE_FRACTION(real_type("3.60555127546398929311922126747049594625129657384524621271045305622716694829301044520461908201849071767351418202406"), r, tol); r = arg(c + 0); BOOST_CHECK_CLOSE_FRACTION(real_type("0.98279372324732906798571061101466601449687745363162855676142508831798807154979603538970653437281731110816513970201"), r, tol); r = norm(c + 0); BOOST_CHECK_CLOSE_FRACTION(real_type(13), r, tol); a = conj(c + 0); BOOST_CHECK_EQUAL(real(a), 2); BOOST_CHECK_EQUAL(imag(a), -3); a = proj(c + 0); BOOST_CHECK_EQUAL(real(a), 2); BOOST_CHECK_EQUAL(imag(a), 3); a = exp(c); BOOST_CHECK_CLOSE_FRACTION(real_type("-7.3151100949011025174865361510507893218698794489446322367845159660828327860599907104337742108443234172141249777"), real(a), tol); BOOST_CHECK_CLOSE_FRACTION(real_type("1.0427436562359044141015039404625521939183300604422348975424523449538886779880818796291971422701951470533151185"), imag(a), tol); a = log(c); BOOST_CHECK_CLOSE_FRACTION(real_type("1.282474678730768368026743720782659302402633972380103558209522755331732333662205089699787331720244744384629096046"), real(a), tol); BOOST_CHECK_CLOSE_FRACTION(real_type("0.9827937232473290679857106110146660144968774536316285567614250883179880715497960353897065343728173111081651397020"), imag(a), tol); a = log10(c); BOOST_CHECK_CLOSE_FRACTION(real_type("0.556971676153418384603252578971164215414864594193534135900595487498776545815097120403823727129449829836488977743"), real(a), tol); BOOST_CHECK_CLOSE_FRACTION(real_type("0.426821890855466638944275673291166123449562356934437957244904971730668088711719757900679614536803436424488603794"), imag(a), tol); a = exp(c + 0); BOOST_CHECK_CLOSE_FRACTION(real_type("-7.3151100949011025174865361510507893218698794489446322367845159660828327860599907104337742108443234172141249777"), real(a), tol); BOOST_CHECK_CLOSE_FRACTION(real_type("1.0427436562359044141015039404625521939183300604422348975424523449538886779880818796291971422701951470533151185"), imag(a), tol); a = log(c + 0); BOOST_CHECK_CLOSE_FRACTION(real_type("1.282474678730768368026743720782659302402633972380103558209522755331732333662205089699787331720244744384629096046"), real(a), tol); BOOST_CHECK_CLOSE_FRACTION(real_type("0.9827937232473290679857106110146660144968774536316285567614250883179880715497960353897065343728173111081651397020"), imag(a), tol); a = log10(c + 0); BOOST_CHECK_CLOSE_FRACTION(real_type("0.556971676153418384603252578971164215414864594193534135900595487498776545815097120403823727129449829836488977743"), real(a), tol); BOOST_CHECK_CLOSE_FRACTION(real_type("0.426821890855466638944275673291166123449562356934437957244904971730668088711719757900679614536803436424488603794"), imag(a), tol); // Powers where one arg is an integer. b = Real(5, -2); a = pow(c, b); BOOST_CHECK_CLOSE_FRACTION(real_type("-3053.8558566606567369633610140423321260211388217942246293871310470377722279440084474789529228008638668934381183"), real(a), tol); BOOST_CHECK_CLOSE_FRACTION(real_type("3097.9975862915005132449772136982559285192410496951232473245540634244845290672745578327467396750607773968246915"), imag(a), tol); a = pow(c, 3); BOOST_CHECK_CLOSE_FRACTION(real_type(-46), real(a), tol); BOOST_CHECK_CLOSE_FRACTION(real_type(9), imag(a), tol); a = pow(3, c); BOOST_CHECK_CLOSE_FRACTION(real_type("-8.8931513442797186948734782808862447235385767991868219480917324534839621090167050538805196124711247247992169338"), real(a), tol); BOOST_CHECK_CLOSE_FRACTION(real_type("-1.3826999557878897572499699021550296885662132089951379549068064961882821777067532977546360861176011175070188118"), imag(a), tol * 3); a = pow(c + 0, b); BOOST_CHECK_CLOSE_FRACTION(real_type("-3053.8558566606567369633610140423321260211388217942246293871310470377722279440084474789529228008638668934381183"), real(a), tol); BOOST_CHECK_CLOSE_FRACTION(real_type("3097.9975862915005132449772136982559285192410496951232473245540634244845290672745578327467396750607773968246915"), imag(a), tol); a = pow(c + 0, 3); BOOST_CHECK_CLOSE_FRACTION(real_type(-46), real(a), tol); BOOST_CHECK_CLOSE_FRACTION(real_type(9), imag(a), tol); a = pow(3, c + 0); BOOST_CHECK_CLOSE_FRACTION(real_type("-8.8931513442797186948734782808862447235385767991868219480917324534839621090167050538805196124711247247992169338"), real(a), tol); BOOST_CHECK_CLOSE_FRACTION(real_type("-1.3826999557878897572499699021550296885662132089951379549068064961882821777067532977546360861176011175070188118"), imag(a), tol * 3); r = 3; // Powers where one arg is a real_type. a = pow(c, r); BOOST_CHECK_CLOSE_FRACTION(real_type(-46), real(a), tol); BOOST_CHECK_CLOSE_FRACTION(real_type(9), imag(a), tol); a = pow(r, c); BOOST_CHECK_CLOSE_FRACTION(real_type("-8.8931513442797186948734782808862447235385767991868219480917324534839621090167050538805196124711247247992169338"), real(a), tol); BOOST_CHECK_CLOSE_FRACTION(real_type("-1.3826999557878897572499699021550296885662132089951379549068064961882821777067532977546360861176011175070188118"), imag(a), tol * 3); a = pow(c + 0, r); BOOST_CHECK_CLOSE_FRACTION(real_type(-46), real(a), tol); BOOST_CHECK_CLOSE_FRACTION(real_type(9), imag(a), tol); a = pow(r, c + 0); BOOST_CHECK_CLOSE_FRACTION(real_type("-8.8931513442797186948734782808862447235385767991868219480917324534839621090167050538805196124711247247992169338"), real(a), tol); BOOST_CHECK_CLOSE_FRACTION(real_type("-1.3826999557878897572499699021550296885662132089951379549068064961882821777067532977546360861176011175070188118"), imag(a), tol * 3); a = pow(c, r + 0); BOOST_CHECK_CLOSE_FRACTION(real_type(-46), real(a), tol); BOOST_CHECK_CLOSE_FRACTION(real_type(9), imag(a), tol); a = pow(r + 0, c); BOOST_CHECK_CLOSE_FRACTION(real_type("-8.8931513442797186948734782808862447235385767991868219480917324534839621090167050538805196124711247247992169338"), real(a), tol); BOOST_CHECK_CLOSE_FRACTION(real_type("-1.3826999557878897572499699021550296885662132089951379549068064961882821777067532977546360861176011175070188118"), imag(a), tol * 3); // Powers where one arg is an float. a = pow(c, 3.0); BOOST_CHECK_CLOSE_FRACTION(real_type(-46), real(a), tol); BOOST_CHECK_CLOSE_FRACTION(real_type(9), imag(a), tol); a = pow(3.0, c); BOOST_CHECK_CLOSE_FRACTION(real_type("-8.8931513442797186948734782808862447235385767991868219480917324534839621090167050538805196124711247247992169338"), real(a), tol); BOOST_CHECK_CLOSE_FRACTION(real_type("-1.3826999557878897572499699021550296885662132089951379549068064961882821777067532977546360861176011175070188118"), imag(a), tol * 3); a = pow(c + 0, 3.0); BOOST_CHECK_CLOSE_FRACTION(real_type(-46), real(a), tol); BOOST_CHECK_CLOSE_FRACTION(real_type(9), imag(a), tol); a = pow(3.0, c + 0); BOOST_CHECK_CLOSE_FRACTION(real_type("-8.8931513442797186948734782808862447235385767991868219480917324534839621090167050538805196124711247247992169338"), real(a), tol); BOOST_CHECK_CLOSE_FRACTION(real_type("-1.3826999557878897572499699021550296885662132089951379549068064961882821777067532977546360861176011175070188118"), imag(a), tol * 3); a = c; a = sqrt(a); BOOST_CHECK_CLOSE_FRACTION(real_type("1.674149228035540040448039300849051821674708677883920366727287836003399240343274891876712629708287692163156802065"), real(a), tol); BOOST_CHECK_CLOSE_FRACTION(real_type("0.8959774761298381247157337552900434410433241995549314932449006989874470582160955817053273057885402621549320588976"), imag(a), tol); a = c; a = sin(a); BOOST_CHECK_CLOSE_FRACTION(real_type("9.154499146911429573467299544609832559158860568765182977899828142590020335321896403936690014669532606510294425039"), real(a), tol); BOOST_CHECK_CLOSE_FRACTION(real_type("-4.168906959966564350754813058853754843573565604758055889965478710592666260138453299795649308385497563475115931624"), imag(a), tol); a = c; a = cos(a); BOOST_CHECK_CLOSE_FRACTION(real_type("-4.1896256909688072301325550196159737286219454041279210357407905058369727912162626993926269783331491034500484583"), real(a), tol); BOOST_CHECK_CLOSE_FRACTION(real_type("-9.1092278937553365979791972627788621213326202389201695649104967309554222940748568716960841549279996556547993373"), imag(a), tol); a = c; a = tan(a); BOOST_CHECK_CLOSE_FRACTION(real_type("-0.0037640256415042482927512211303226908396306202016580864328644932511249097100916559688254811519914564480500042311"), real(a), tol * 5); BOOST_CHECK_CLOSE_FRACTION(real_type("1.0032386273536098014463585978219272598077897241071003399272426939850671219193120708438426543945017427085738411"), imag(a), tol); a = c; a = asin(a); BOOST_CHECK_CLOSE_FRACTION(real_type("0.5706527843210994007102838796856696501828032450960401365302732598209740064262509342420347149436326252483895113827"), real(a), tol); BOOST_CHECK_CLOSE_FRACTION(real_type("1.983387029916535432347076902894039565014248302909345356125267430944752731616095111727103650117987412058949254132"), imag(a), tol); a = c; a = acos(a); BOOST_CHECK_CLOSE_FRACTION(real_type("1.000143542473797218521037811954081791915781454591512773957199036332934196716853565071982697727425908742684531873"), real(a), tol); BOOST_CHECK_CLOSE_FRACTION(real_type("-1.983387029916535432347076902894039565014248302909345356125267430944752731616095111727103650117987412058949254132"), imag(a), tol); a = c; a = atan(a); BOOST_CHECK_CLOSE_FRACTION(real_type("1.409921049596575522530619384460420782588207051908724814771070766475530084440199227135813201495737846771570458568"), real(a), tol); BOOST_CHECK_CLOSE_FRACTION(real_type("0.2290726829685387662958818029420027678625253049770656169479919704951963414344907622560676377741902308144912055002"), imag(a), tol); a = c; a = sqrt(a + 0); BOOST_CHECK_CLOSE_FRACTION(real_type("1.674149228035540040448039300849051821674708677883920366727287836003399240343274891876712629708287692163156802065"), real(a), tol); BOOST_CHECK_CLOSE_FRACTION(real_type("0.8959774761298381247157337552900434410433241995549314932449006989874470582160955817053273057885402621549320588976"), imag(a), tol); a = c; a = sin(a + 0); BOOST_CHECK_CLOSE_FRACTION(real_type("9.154499146911429573467299544609832559158860568765182977899828142590020335321896403936690014669532606510294425039"), real(a), tol); BOOST_CHECK_CLOSE_FRACTION(real_type("-4.168906959966564350754813058853754843573565604758055889965478710592666260138453299795649308385497563475115931624"), imag(a), tol); a = c; a = cos(a + 0); BOOST_CHECK_CLOSE_FRACTION(real_type("-4.1896256909688072301325550196159737286219454041279210357407905058369727912162626993926269783331491034500484583"), real(a), tol); BOOST_CHECK_CLOSE_FRACTION(real_type("-9.1092278937553365979791972627788621213326202389201695649104967309554222940748568716960841549279996556547993373"), imag(a), tol); a = c; a = tan(a + 0); BOOST_CHECK_CLOSE_FRACTION(real_type("-0.0037640256415042482927512211303226908396306202016580864328644932511249097100916559688254811519914564480500042311"), real(a), tol * 5); BOOST_CHECK_CLOSE_FRACTION(real_type("1.0032386273536098014463585978219272598077897241071003399272426939850671219193120708438426543945017427085738411"), imag(a), tol); a = c; a = asin(a + 0); BOOST_CHECK_CLOSE_FRACTION(real_type("0.5706527843210994007102838796856696501828032450960401365302732598209740064262509342420347149436326252483895113827"), real(a), tol); BOOST_CHECK_CLOSE_FRACTION(real_type("1.983387029916535432347076902894039565014248302909345356125267430944752731616095111727103650117987412058949254132"), imag(a), tol); a = c; a = acos(a + 0); BOOST_CHECK_CLOSE_FRACTION(real_type("1.000143542473797218521037811954081791915781454591512773957199036332934196716853565071982697727425908742684531873"), real(a), tol); BOOST_CHECK_CLOSE_FRACTION(real_type("-1.983387029916535432347076902894039565014248302909345356125267430944752731616095111727103650117987412058949254132"), imag(a), tol); a = c; a = atan(a + 0); BOOST_CHECK_CLOSE_FRACTION(real_type("1.409921049596575522530619384460420782588207051908724814771070766475530084440199227135813201495737846771570458568"), real(a), tol); BOOST_CHECK_CLOSE_FRACTION(real_type("0.2290726829685387662958818029420027678625253049770656169479919704951963414344907622560676377741902308144912055002"), imag(a), tol); a = c; a = sinh(a); BOOST_CHECK_CLOSE_FRACTION(real_type("-3.5905645899857799520125654477948167931949136757293015099986213974178826801534614215227593814301490087307920223"), real(a), tol); BOOST_CHECK_CLOSE_FRACTION(real_type("0.53092108624851980526704009066067655967277345095149103008706855371803528753067068552935673000832252607835087747"), imag(a), tol); a = c; a = cosh(a); BOOST_CHECK_CLOSE_FRACTION(real_type("-3.7245455049153225654739707032559725286749657732153307267858945686649501059065292889110148294141744084833329553"), real(a), tol); BOOST_CHECK_CLOSE_FRACTION(real_type("0.51182256998738460883446384980187563424555660949074386745538379123585339045741119409984041226187262097496424111"), imag(a), tol); a = c; a = tanh(a); BOOST_CHECK_CLOSE_FRACTION(real_type("0.965385879022133124278480269394560685879729650005757773636908240066639772853967550095754361348005358178253777920"), real(a), tol * 5); BOOST_CHECK_CLOSE_FRACTION(real_type("-0.00988437503832249372031403430350121097961813353467039031861010606115560355679254344335582852193041894874685555114"), imag(a), tol); a = c; a = asinh(a); BOOST_CHECK_CLOSE_FRACTION(real_type("1.968637925793096291788665095245498189520731012682010573842811017352748255492485345887875752070076230641308014923"), real(a), tol); BOOST_CHECK_CLOSE_FRACTION(real_type("0.9646585044076027920454110594995323555197773725073316527132580297155508786089335572049608301897631767195194427315"), imag(a), tol); a = c; a = acosh(a); BOOST_CHECK_CLOSE_FRACTION(real_type("1.983387029916535432347076902894039565014248302909345356125267430944752731616095111727103650117987412058949254132"), real(a), tol); BOOST_CHECK_CLOSE_FRACTION(real_type("1.000143542473797218521037811954081791915781454591512773957199036332934196716853565071982697727425908742684531873"), imag(a), tol); a = c; a = atanh(a); BOOST_CHECK_CLOSE_FRACTION(real_type("0.1469466662255297520474327851547159424423449403442452953891851939502023996823900422792744078835711416939934387775"), real(a), tol); BOOST_CHECK_CLOSE_FRACTION(real_type("1.338972522294493561124193575909144241084316172544492778582005751793809271060233646663717270678614587712809117131"), imag(a), tol); a = c; a = sinh(a + 0); BOOST_CHECK_CLOSE_FRACTION(real_type("-3.5905645899857799520125654477948167931949136757293015099986213974178826801534614215227593814301490087307920223"), real(a), tol); BOOST_CHECK_CLOSE_FRACTION(real_type("0.53092108624851980526704009066067655967277345095149103008706855371803528753067068552935673000832252607835087747"), imag(a), tol); a = c; a = cosh(a + 0); BOOST_CHECK_CLOSE_FRACTION(real_type("-3.7245455049153225654739707032559725286749657732153307267858945686649501059065292889110148294141744084833329553"), real(a), tol); BOOST_CHECK_CLOSE_FRACTION(real_type("0.51182256998738460883446384980187563424555660949074386745538379123585339045741119409984041226187262097496424111"), imag(a), tol); a = c; a = tanh(a + 0); BOOST_CHECK_CLOSE_FRACTION(real_type("0.965385879022133124278480269394560685879729650005757773636908240066639772853967550095754361348005358178253777920"), real(a), tol); BOOST_CHECK_CLOSE_FRACTION(real_type("-0.00988437503832249372031403430350121097961813353467039031861010606115560355679254344335582852193041894874685555114"), imag(a), tol); a = c; a = asinh(a + 0); BOOST_CHECK_CLOSE_FRACTION(real_type("1.968637925793096291788665095245498189520731012682010573842811017352748255492485345887875752070076230641308014923"), real(a), tol); BOOST_CHECK_CLOSE_FRACTION(real_type("0.9646585044076027920454110594995323555197773725073316527132580297155508786089335572049608301897631767195194427315"), imag(a), tol); a = c; a = acosh(a + 0); BOOST_CHECK_CLOSE_FRACTION(real_type("1.983387029916535432347076902894039565014248302909345356125267430944752731616095111727103650117987412058949254132"), real(a), tol); BOOST_CHECK_CLOSE_FRACTION(real_type("1.000143542473797218521037811954081791915781454591512773957199036332934196716853565071982697727425908742684531873"), imag(a), tol); a = c; a = atanh(a + 0); BOOST_CHECK_CLOSE_FRACTION(real_type("0.1469466662255297520474327851547159424423449403442452953891851939502023996823900422792744078835711416939934387775"), real(a), tol); BOOST_CHECK_CLOSE_FRACTION(real_type("1.338972522294493561124193575909144241084316172544492778582005751793809271060233646663717270678614587712809117131"), imag(a), tol); } template typename std::enable_if::value != boost::multiprecision::number_kind_complex>::type test_members(Real) { // // Test sign and zero functions: // Real a = 20; Real b = 30; BOOST_CHECK(a.sign() > 0); BOOST_CHECK(!a.is_zero()); BOOST_IF_CONSTEXPR (std::numeric_limits::is_signed) { a = -20; BOOST_CHECK(a.sign() < 0); BOOST_CHECK(!a.is_zero()); } a = 0; BOOST_CHECK_EQUAL(a.sign(), 0); BOOST_CHECK(a.is_zero()); a = 20; b = 30; a.swap(b); BOOST_CHECK_EQUAL(a, 30); BOOST_CHECK_EQUAL(b, 20); // // Test complex number functions which are also overloaded for scalar type: // BOOST_CHECK_EQUAL(real(a), a); BOOST_CHECK_EQUAL(imag(a), 0); BOOST_CHECK_EQUAL(real(a + 0), a); BOOST_CHECK_EQUAL(imag(a + 2), 0); BOOST_CHECK_EQUAL(norm(a), a * a); BOOST_CHECK_EQUAL(norm(a * 1), a * a); BOOST_CHECK_EQUAL(conj(a), a); BOOST_CHECK_EQUAL(conj(a * 1), a); BOOST_CHECK_EQUAL(proj(a), a); BOOST_CHECK_EQUAL(proj(a * 1), a); BOOST_CHECK_EQUAL(a.real(), a); BOOST_CHECK_EQUAL(a.imag(), 0); a.real(55); BOOST_CHECK_EQUAL(a, 55); } template void test_members(boost::rational) { } template void test_signed_ops(const std::integral_constant&) { Real a(8); Real b(64); Real c(500); Real d(1024); Real ac; BOOST_CHECK_EQUAL(-a, -8); ac = a; ac = ac - b; BOOST_CHECK_EQUAL(ac, 8 - 64); ac = a; ac -= a + b; BOOST_CHECK_EQUAL(ac, -64); ac = a; ac -= b - a; BOOST_CHECK_EQUAL(ac, 16 - 64); ac = -a; BOOST_CHECK_EQUAL(ac, -8); ac = a; ac -= -a; BOOST_CHECK_EQUAL(ac, 16); ac = a; ac += -a; BOOST_CHECK_EQUAL(ac, 0); ac = b; ac /= -a; BOOST_CHECK_EQUAL(ac, -8); ac = a; ac *= -a; BOOST_CHECK_EQUAL(ac, -64); ac = a + -b; BOOST_CHECK_EQUAL(ac, 8 - 64); ac = -a + b; BOOST_CHECK_EQUAL(ac, -8 + 64); ac = -a + -b; BOOST_CHECK_EQUAL(ac, -72); ac = a + -+-b; // lots of unary operators!! BOOST_CHECK_EQUAL(ac, 72); test_conditional(Real(-a), -a); // // RValue ref tests: // a = 3; b = 4; c = Real(20) + -(a + b); BOOST_CHECK_EQUAL(c, 13); c = Real(20) + -a; BOOST_CHECK_EQUAL(c, 17); c = -a + Real(20); BOOST_CHECK_EQUAL(c, 17); c = -a + b; BOOST_CHECK_EQUAL(c, 1); c = b + -a; BOOST_CHECK_EQUAL(c, 1); a = 2; b = 3; c = Real(10) - a; BOOST_CHECK_EQUAL(c, 8); c = a - Real(2); BOOST_CHECK_EQUAL(c, 0); c = Real(3) - Real(2); BOOST_CHECK_EQUAL(c, 1); a = 20; c = a - (a + b); BOOST_CHECK_EQUAL(c, -3); a = 2; c = (a * b) - (a + b); BOOST_CHECK_EQUAL(c, 1); c = Real(20) - -(a + b); BOOST_CHECK_EQUAL(c, 25); c = Real(20) - (-a); BOOST_CHECK_EQUAL(c, 22); c = (-b) - Real(-5); BOOST_CHECK_EQUAL(c, 2); c = (-b) - a; BOOST_CHECK_EQUAL(c, -5); c = b - (-a); BOOST_CHECK_EQUAL(c, 5); c = Real(3) * -(a + b); BOOST_CHECK_EQUAL(c, -15); c = -(a + b) * Real(3); BOOST_CHECK_EQUAL(c, -15); c = Real(2) * -a; BOOST_CHECK_EQUAL(c, -4); c = -a * Real(2); BOOST_CHECK_EQUAL(c, -4); c = -a * b; BOOST_CHECK_EQUAL(c, -6); a = 2; b = 4; c = Real(4) / -a; BOOST_CHECK_EQUAL(c, -2); c = -b / Real(2); BOOST_CHECK_EQUAL(c, -2); c = Real(4) / -(2 * a); BOOST_CHECK_EQUAL(c, -1); c = b / -(2 * a); BOOST_CHECK_EQUAL(c, -1); c = -(2 * a) / Real(2); BOOST_CHECK_EQUAL(c, -2); } template void test_signed_ops(const std::integral_constant&) { } template void test_basic_conditionals(Real a, Real b) { if (a) { BOOST_ERROR("Unexpected non-zero result"); } if (!a) { } else { BOOST_ERROR("Unexpected zero result"); } b = 2; if (!b) { BOOST_ERROR("Unexpected zero result"); } if (b) { } else { BOOST_ERROR("Unexpected non-zero result"); } if (a && b) { BOOST_ERROR("Unexpected zero result"); } if (!(a || b)) { BOOST_ERROR("Unexpected zero result"); } if (a + b) { } else { BOOST_ERROR("Unexpected zero result"); } if (b - 2) { BOOST_ERROR("Unexpected non-zero result"); } } template typename std::enable_if::value == boost::multiprecision::number_kind_complex>::type test_comparisons(T a, T b) { BOOST_CHECK_EQUAL((a == b), false); BOOST_CHECK_EQUAL((a != b), true); BOOST_CHECK_EQUAL((a + b == b), false); BOOST_CHECK_EQUAL((a + b != b), true); BOOST_CHECK_EQUAL((a == b + a), false); BOOST_CHECK_EQUAL((a != b + a), true); BOOST_CHECK_EQUAL((a + b == b + a), true); BOOST_CHECK_EQUAL((a + b != b + a), false); BOOST_CHECK_EQUAL((8 == b + a), false); BOOST_CHECK_EQUAL((8 != b + a), true); BOOST_CHECK_EQUAL((800 == b + a), false); BOOST_CHECK_EQUAL((800 != b + a), true); BOOST_CHECK_EQUAL((72 == b + a), true); BOOST_CHECK_EQUAL((72 != b + a), false); BOOST_CHECK_EQUAL((b + a == 8), false); BOOST_CHECK_EQUAL((b + a != 8), true); BOOST_CHECK_EQUAL((b + a == 800), false); BOOST_CHECK_EQUAL((b + a != 800), true); BOOST_CHECK_EQUAL((b + a == 72), true); BOOST_CHECK_EQUAL((b + a != 72), false); } template typename std::enable_if::value != boost::multiprecision::number_kind_complex>::type test_comparisons(T a, T b) { BOOST_CHECK_EQUAL((a == b), false); BOOST_CHECK_EQUAL((a != b), true); BOOST_CHECK_EQUAL((a <= b), true); BOOST_CHECK_EQUAL((a < b), true); BOOST_CHECK_EQUAL((a >= b), false); BOOST_CHECK_EQUAL((a > b), false); BOOST_CHECK_EQUAL((a + b == b), false); BOOST_CHECK_EQUAL((a + b != b), true); BOOST_CHECK_EQUAL((a + b >= b), true); BOOST_CHECK_EQUAL((a + b > b), true); BOOST_CHECK_EQUAL((a + b <= b), false); BOOST_CHECK_EQUAL((a + b < b), false); BOOST_CHECK_EQUAL((a == b + a), false); BOOST_CHECK_EQUAL((a != b + a), true); BOOST_CHECK_EQUAL((a <= b + a), true); BOOST_CHECK_EQUAL((a < b + a), true); BOOST_CHECK_EQUAL((a >= b + a), false); BOOST_CHECK_EQUAL((a > b + a), false); BOOST_CHECK_EQUAL((a + b == b + a), true); BOOST_CHECK_EQUAL((a + b != b + a), false); BOOST_CHECK_EQUAL((a + b <= b + a), true); BOOST_CHECK_EQUAL((a + b < b + a), false); BOOST_CHECK_EQUAL((a + b >= b + a), true); BOOST_CHECK_EQUAL((a + b > b + a), false); BOOST_CHECK_EQUAL((8 == b + a), false); BOOST_CHECK_EQUAL((8 != b + a), true); BOOST_CHECK_EQUAL((8 <= b + a), true); BOOST_CHECK_EQUAL((8 < b + a), true); BOOST_CHECK_EQUAL((8 >= b + a), false); BOOST_CHECK_EQUAL((8 > b + a), false); BOOST_CHECK_EQUAL((800 == b + a), false); BOOST_CHECK_EQUAL((800 != b + a), true); BOOST_CHECK_EQUAL((800 >= b + a), true); BOOST_CHECK_EQUAL((800 > b + a), true); BOOST_CHECK_EQUAL((800 <= b + a), false); BOOST_CHECK_EQUAL((800 < b + a), false); BOOST_CHECK_EQUAL((72 == b + a), true); BOOST_CHECK_EQUAL((72 != b + a), false); BOOST_CHECK_EQUAL((72 <= b + a), true); BOOST_CHECK_EQUAL((72 < b + a), false); BOOST_CHECK_EQUAL((72 >= b + a), true); BOOST_CHECK_EQUAL((72 > b + a), false); BOOST_CHECK_EQUAL((b + a == 8), false); BOOST_CHECK_EQUAL((b + a != 8), true); BOOST_CHECK_EQUAL((b + a >= 8), true); BOOST_CHECK_EQUAL((b + a > 8), true); BOOST_CHECK_EQUAL((b + a <= 8), false); BOOST_CHECK_EQUAL((b + a < 8), false); BOOST_CHECK_EQUAL((b + a == 800), false); BOOST_CHECK_EQUAL((b + a != 800), true); BOOST_CHECK_EQUAL((b + a <= 800), true); BOOST_CHECK_EQUAL((b + a < 800), true); BOOST_CHECK_EQUAL((b + a >= 800), false); BOOST_CHECK_EQUAL((b + a > 800), false); BOOST_CHECK_EQUAL((b + a == 72), true); BOOST_CHECK_EQUAL((b + a != 72), false); BOOST_CHECK_EQUAL((b + a >= 72), true); BOOST_CHECK_EQUAL((b + a > 72), false); BOOST_CHECK_EQUAL((b + a <= 72), true); BOOST_CHECK_EQUAL((b + a < 72), false); T c; // // min and max overloads: // #if !defined(min) && !defined(max) // using std::max; // using std::min; // This works, but still causes complaints from inspect.exe, so use brackets to prevent macrosubstitution, // and to explicitly specify type T seems necessary, for reasons unclear. a = 2; b = 5; c = 6; BOOST_CHECK_EQUAL((std::min)(a, b), a); BOOST_CHECK_EQUAL((std::min)(b, a), a); BOOST_CHECK_EQUAL((std::max)(a, b), b); BOOST_CHECK_EQUAL((std::max)(b, a), b); BOOST_CHECK_EQUAL((std::min)(a, b + c), a); BOOST_CHECK_EQUAL((std::min)(b + c, a), a); BOOST_CHECK_EQUAL((std::min)(a, c - b), 1); BOOST_CHECK_EQUAL((std::min)(c - b, a), 1); BOOST_CHECK_EQUAL((std::max)(a, b + c), 11); BOOST_CHECK_EQUAL((std::max)(b + c, a), 11); BOOST_CHECK_EQUAL((std::max)(a, c - b), a); BOOST_CHECK_EQUAL((std::max)(c - b, a), a); BOOST_CHECK_EQUAL((std::min)(a + b, b + c), 7); BOOST_CHECK_EQUAL((std::min)(b + c, a + b), 7); BOOST_CHECK_EQUAL((std::max)(a + b, b + c), 11); BOOST_CHECK_EQUAL((std::max)(b + c, a + b), 11); BOOST_CHECK_EQUAL((std::min)(a + b, c - a), 4); BOOST_CHECK_EQUAL((std::min)(c - a, a + b), 4); BOOST_CHECK_EQUAL((std::max)(a + b, c - a), 7); BOOST_CHECK_EQUAL((std::max)(c - a, a + b), 7); long l1(2), l2(3), l3; l3 = (std::min)(l1, l2) + (std::max)(l1, l2) + (std::max)(l1, l2) + (std::min)(l1, l2); BOOST_CHECK_EQUAL(l3, 10); #endif } template const T& self(const T& a) { return a; } template void test() { #if !defined(NO_MIXED_OPS) && !defined(SLOW_COMPILER) boost::multiprecision::is_number tag; test_mixed(tag); test_mixed(tag); test_mixed(tag); test_mixed(tag); test_mixed(tag); test_mixed(tag); test_mixed(tag); test_mixed(tag); test_mixed(tag); #ifdef BOOST_HAS_LONG_LONG test_mixed(tag); test_mixed(tag); #endif #if defined(BOOST_HAS_INT128) && !defined(BOOST_NO_CXX17_IF_CONSTEXPR) #if (defined(__GNUC__) && !defined(__clang__)) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wpedantic" #endif if constexpr (std::is_constructible::value) { test_mixed(tag); test_mixed(tag); } #if (defined(__GNUC__) && !defined(__clang__)) #pragma GCC diagnostic pop #endif #endif test_mixed(tag); test_mixed(tag); test_mixed(tag); #if defined(BOOST_HAS_FLOAT128) && !defined(BOOST_NO_CXX17_IF_CONSTEXPR) //if constexpr (std::is_constructible::value) // test_mixed(tag); #endif typedef typename related_type::type related_type; std::integral_constant::value && !std::is_same::value> tag2; test_mixed(tag2); std::integral_constant::value && (boost::multiprecision::number_category::value == boost::multiprecision::number_kind_complex)> complex_tag; test_mixed >(complex_tag); test_mixed >(complex_tag); test_mixed >(complex_tag); test_enum_conversions(); #endif #ifndef MIXED_OPS_ONLY // // Integer only functions: // test_integer_ops(typename boost::multiprecision::number_category::type()); // // Real number only functions: // test_float_ops(typename boost::multiprecision::number_category::type()); // // Test basic arithmetic: // Real a(8); Real b(64); Real c(500); Real d(1024); BOOST_CHECK_EQUAL(a + b, 72); a += b; BOOST_CHECK_EQUAL(a, 72); BOOST_CHECK_EQUAL(a - b, 8); a -= b; BOOST_CHECK_EQUAL(a, 8); BOOST_CHECK_EQUAL(a * b, 8 * 64L); a *= b; BOOST_CHECK_EQUAL(a, 8 * 64L); BOOST_CHECK_EQUAL(a / b, 8); a /= b; BOOST_CHECK_EQUAL(a, 8); Real ac(a); BOOST_CHECK_EQUAL(ac, a); ac = a * c; BOOST_CHECK_EQUAL(ac, 8 * 500L); ac = 8 * 500L; ac = ac + b + c; BOOST_CHECK_EQUAL(ac, 8 * 500L + 64 + 500); ac = a; ac = b + c + ac; BOOST_CHECK_EQUAL(ac, 8 + 64 + 500); ac = ac - b + c; BOOST_CHECK_EQUAL(ac, 8 + 64 + 500 - 64 + 500); ac = a; ac = b + c - ac; BOOST_CHECK_EQUAL(ac, -8 + 64 + 500); ac = a; ac = ac * b; BOOST_CHECK_EQUAL(ac, 8 * 64); ac = a; ac *= b * ac; BOOST_CHECK_EQUAL(ac, 8 * 8 * 64); ac = b; ac = ac / a; BOOST_CHECK_EQUAL(ac, 64 / 8); ac = b; ac /= ac / a; BOOST_CHECK_EQUAL(ac, 64 / (64 / 8)); ac = a; ac = b + ac * a; BOOST_CHECK_EQUAL(ac, 64 * 2); ac = a; ac = b - ac * a; BOOST_CHECK_EQUAL(ac, 0); ac = a; ac = b * (ac + a); BOOST_CHECK_EQUAL(ac, 64 * (16)); ac = a; ac = b / (ac * 1); BOOST_CHECK_EQUAL(ac, 64 / 8); ac = a; ac = ac + b; BOOST_CHECK_EQUAL(ac, 8 + 64); ac = a; ac = a + ac; BOOST_CHECK_EQUAL(ac, 16); ac = a; ac = a - ac; BOOST_CHECK_EQUAL(ac, 0); ac = a; ac += a + b; BOOST_CHECK_EQUAL(ac, 80); ac = a; ac += b + a; BOOST_CHECK_EQUAL(ac, 80); ac = +a; BOOST_CHECK_EQUAL(ac, 8); ac = 8; ac = a * ac; BOOST_CHECK_EQUAL(ac, 8 * 8); ac = a; ac = a; ac += +a; BOOST_CHECK_EQUAL(ac, 16); ac = a; ac += b - a; BOOST_CHECK_EQUAL(ac, 8 + 64 - 8); ac = a; ac += b * c; BOOST_CHECK_EQUAL(ac, 8 + 64 * 500); ac = a; ac = a; ac -= +a; BOOST_CHECK_EQUAL(ac, 0); ac = a; BOOST_IF_CONSTEXPR (std::numeric_limits::is_signed || is_twos_complement_integer::value) { ac = a; ac -= c - b; BOOST_CHECK_EQUAL(ac, 8 - (500 - 64)); ac = a; ac -= b * c; BOOST_CHECK_EQUAL(ac, 8 - 500 * 64); } ac = a; ac += ac * b; BOOST_CHECK_EQUAL(ac, 8 + 8 * 64); BOOST_IF_CONSTEXPR (std::numeric_limits::is_signed || is_twos_complement_integer::value) { ac = a; ac -= ac * b; BOOST_CHECK_EQUAL(ac, 8 - 8 * 64); } ac = a * 8; ac *= +a; BOOST_CHECK_EQUAL(ac, 64 * 8); ac = a; ac *= b * c; BOOST_CHECK_EQUAL(ac, 8 * 64 * 500); ac = a; ac *= b / a; BOOST_CHECK_EQUAL(ac, 8 * 64 / 8); ac = a; ac *= b + c; BOOST_CHECK_EQUAL(ac, 8 * (64 + 500)); ac = b; ac /= +a; BOOST_CHECK_EQUAL(ac, 8); ac = b; ac /= b / a; BOOST_CHECK_EQUAL(ac, 64 / (64 / 8)); ac = b; ac /= a + Real(0); BOOST_CHECK_EQUAL(ac, 8); // // simple tests with immediate values, these calls can be optimised in many backends: // ac = a + b; BOOST_CHECK_EQUAL(ac, 72); ac = a + +b; BOOST_CHECK_EQUAL(ac, 72); ac = +a + b; BOOST_CHECK_EQUAL(ac, 72); ac = +a + +b; BOOST_CHECK_EQUAL(ac, 72); ac = a; ac = b / ac; BOOST_CHECK_EQUAL(ac, b / a); // // Comparisons: // test_comparisons(a, b); test_members(a); // // Use in Boolean context: // a = 0; b = 2; test_basic_conditionals(a, b); // // Test iostreams: // std::stringstream ss; a = 20; b = 2; ss << a; ss >> c; BOOST_CHECK_EQUAL(a, c); ss.clear(); ss << a + b; ss >> c; BOOST_CHECK_EQUAL(c, 22); BOOST_CHECK_EQUAL(c, a + b); // // More cases for complete code coverage: // a = 20; b = 30; swap(a, b); BOOST_CHECK_EQUAL(a, 30); BOOST_CHECK_EQUAL(b, 20); a = 20; b = 30; std::swap(a, b); BOOST_CHECK_EQUAL(a, 30); BOOST_CHECK_EQUAL(b, 20); a = 20; b = 30; a = a + b * 2; BOOST_CHECK_EQUAL(a, 20 + 30 * 2); a = 100; a = a - b * 2; BOOST_CHECK_EQUAL(a, 100 - 30 * 2); a = 20; a = a * (b + 2); BOOST_CHECK_EQUAL(a, 20 * (32)); a = 20; a = (b + 2) * a; BOOST_CHECK_EQUAL(a, 20 * (32)); a = 90; b = 2; a = a / (b + 0); BOOST_CHECK_EQUAL(a, 45); a = 20; b = 30; c = (a * b) + 22; BOOST_CHECK_EQUAL(c, 20 * 30 + 22); c = 22 + (a * b); BOOST_CHECK_EQUAL(c, 20 * 30 + 22); c = 10; ac = a + b * c; BOOST_CHECK_EQUAL(ac, 20 + 30 * 10); ac = b * c + a; BOOST_CHECK_EQUAL(ac, 20 + 30 * 10); a = a + b * c; BOOST_CHECK_EQUAL(a, 20 + 30 * 10); a = 20; b = a + b * c; BOOST_CHECK_EQUAL(b, 20 + 30 * 10); b = 30; c = a + b * c; BOOST_CHECK_EQUAL(c, 20 + 30 * 10); c = 10; c = a + b / c; BOOST_CHECK_EQUAL(c, 20 + 30 / 10); // // Additional tests for rvalue ref overloads: // a = 3; b = 4; c = Real(2) + a; BOOST_CHECK_EQUAL(c, 5); c = a + Real(2); BOOST_CHECK_EQUAL(c, 5); c = Real(3) + Real(2); BOOST_CHECK_EQUAL(c, 5); c = Real(2) + (a + b); BOOST_CHECK_EQUAL(c, 9); c = (a + b) + Real(2); BOOST_CHECK_EQUAL(c, 9); c = (a + b) + (a + b); BOOST_CHECK_EQUAL(c, 14); c = a * Real(4); BOOST_CHECK_EQUAL(c, 12); c = Real(3) * Real(4); BOOST_CHECK_EQUAL(c, 12); c = (a + b) * (a + b); BOOST_CHECK_EQUAL(c, 49); a = 2; c = b / Real(2); BOOST_CHECK_EQUAL(c, 2); c = Real(4) / a; BOOST_CHECK_EQUAL(c, 2); c = Real(4) / Real(2); BOOST_CHECK_EQUAL(c, 2); // // Test conditionals: // a = 20; test_conditional(a, +a); test_conditional(a, (a + 0)); test_signed_ops(std::integral_constant::is_signed>()); // // Test hashing: // std::hash hasher; std::size_t s = hasher(a); BOOST_CHECK_NE(s, 0); std::hash hasher2; s = hasher2(a); BOOST_CHECK_NE(s, 0); // // Test move: // Real m(static_cast(a)); BOOST_CHECK_EQUAL(m, 20); // Move from already moved from object: Real m2(static_cast(a)); // assign from moved from object // (may result in "a" being left in valid state as implementation artifact): c = static_cast(a); // assignment to moved-from objects: c = static_cast(m); BOOST_CHECK_EQUAL(c, 20); m2 = c; BOOST_CHECK_EQUAL(c, 20); // Destructor of "a" checks destruction of moved-from-object... Real m3(static_cast(a)); #ifndef BOOST_MP_NOT_TESTING_NUMBER // // string and string_view: // { std::string s1("2"); Real x(s1); BOOST_CHECK_EQUAL(x, 2); s1 = "3"; x.assign(s1); BOOST_CHECK_EQUAL(x, 3); #ifndef BOOST_NO_CXX17_HDR_STRING_VIEW s1 = "20"; std::string_view v(s1.c_str(), 1); Real y(v); BOOST_CHECK_EQUAL(y, 2); std::string_view v2(s1.c_str(), 2); y.assign(v2); BOOST_CHECK_EQUAL(y, 20); #endif } #endif // // Bug cases, self assignment first: // a = 20; a = self(a); BOOST_CHECK_EQUAL(a, 20); a = 2; a = a * a * a; BOOST_CHECK_EQUAL(a, 8); a = 2; a = a + a + a; BOOST_CHECK_EQUAL(a, 6); a = 2; a = a - a + a; BOOST_CHECK_EQUAL(a, 2); a = 2; a = a + a - a; BOOST_CHECK_EQUAL(a, 2); a = 2; a = a * a - a; BOOST_CHECK_EQUAL(a, 2); a = 2; a = a + a * a; BOOST_CHECK_EQUAL(a, 6); a = 2; a = (a + a) * a; BOOST_CHECK_EQUAL(a, 8); #endif } ================================================ FILE: test/test_uintwide_t.h ================================================ /////////////////////////////////////////////////////////////////// // Copyright Christopher Kormanyos 2019 - 2025. // // Distributed under the Boost Software License, // // Version 1.0. (See accompanying file LICENSE_1_0.txt // // or copy at http://www.boost.org/LICENSE_1_0.txt) // /////////////////////////////////////////////////////////////////// #ifndef TEST_UINTWIDE_T_2019_12_15_H // NOLINT(llvm-header-guard) #define TEST_UINTWIDE_T_2019_12_15_H #include WIDE_INTEGER_NAMESPACE_BEGIN #if(__cplusplus >= 201703L) namespace math::wide_integer { #else namespace math { namespace wide_integer { // NOLINT(modernize-concat-nested-namespaces) #endif auto test_uintwide_t_boost_backend() -> bool; auto test_uintwide_t_examples () -> bool; auto test_uintwide_t_edge_cases () -> bool; auto test_uintwide_t_float_convert() -> bool; auto test_uintwide_t_int_convert () -> bool; auto test_uintwide_t_spot_values () -> bool; #if(__cplusplus >= 201703L) } // namespace math::wide_integer #else } // namespace wide_integer } // namespace math #endif WIDE_INTEGER_NAMESPACE_END #endif // TEST_UINTWIDE_T_2019_12_15_H ================================================ FILE: test/test_uintwide_t_boost_backend.cpp ================================================ /////////////////////////////////////////////////////////////////////////////// // Copyright Christopher Kormanyos 2019 - 2025. // Distributed under the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt // or copy at http://www.boost.org/LICENSE_1_0.txt) // #include #if !defined(BOOST_VERSION) #error BOOST_VERSION is not defined. Ensure that is properly included. #endif #if ((BOOST_VERSION >= 107900) && !defined(BOOST_MP_STANDALONE)) #define BOOST_MP_STANDALONE #endif #if ((BOOST_VERSION >= 108000) && !defined(BOOST_NO_EXCEPTIONS)) #define BOOST_NO_EXCEPTIONS #endif #if (((BOOST_VERSION == 108000) || (BOOST_VERSION == 108100)) && defined(BOOST_NO_EXCEPTIONS)) #if defined(__clang__) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wsometimes-uninitialized" #endif #if defined(_MSC_VER) #pragma warning(push) #pragma warning(disable : 4701) #endif #endif #if (BOOST_VERSION < 108000) #if defined(__GNUC__) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wconversion" #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wsign-conversion" #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wunused-parameter" #endif #endif #if (defined(__GNUC__) && !defined(__clang__) && (__GNUC__ >= 12)) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wrestrict" #endif #if (BOOST_VERSION < 108000) #if ((defined(__clang__) && (__clang_major__ > 9)) && !defined(__APPLE__)) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wdeprecated-copy" #endif #endif #include #include #include using local_uint_type = #if defined(WIDE_INTEGER_NAMESPACE) boost::multiprecision::number(UINT32_C(1024))>, boost::multiprecision::et_off>; #else boost::multiprecision::number(UINT32_C(1024))>, boost::multiprecision::et_off>; #endif using boost_uint_backend_type = boost::multiprecision::cpp_int_backend(UINT32_C(1024)), static_cast(UINT32_C(1024)), boost::multiprecision::unsigned_magnitude>; using boost_uint_type = boost::multiprecision::number; #if defined(WIDE_INTEGER_NAMESPACE) auto WIDE_INTEGER_NAMESPACE::math::wide_integer::test_uintwide_t_boost_backend() -> bool #else auto ::math::wide_integer::test_uintwide_t_boost_backend() -> bool #endif { bool result_is_ok = true; // Test a non-trivial calculation. A naive algorithm for calculating // a factorial (in this case 100!) has been selected. { local_uint_type u = 1U; for(auto i = static_cast(UINT32_C(2)); i <= static_cast(UINT32_C(100)); ++i) { u *= i; } const local_uint_type local_control("93326215443944152681699238856266700490715968264381621468592963895217599993229915608941463976156518286253697920827223758251185210916864000000000000000000000000"); const boost_uint_type boost_control("93326215443944152681699238856266700490715968264381621468592963895217599993229915608941463976156518286253697920827223758251185210916864000000000000000000000000"); const bool local_control_is_ok = (u == local_control); { std::stringstream strm_lhs; strm_lhs << u; std::stringstream strm_rhs; strm_rhs << boost_control; const bool boost_control_is_ok = (strm_lhs.str() == strm_rhs.str()); result_is_ok = ((local_control_is_ok && boost_control_is_ok) && result_is_ok); } // Test divide-by-limb. u /= static_cast(UINT8_C(10)); result_is_ok = ((u == local_uint_type("9332621544394415268169923885626670049071596826438162146859296389521759999322991560894146397615651828625369792082722375825118521091686400000000000000000000000")) && result_is_ok); // Test full multiplication. u *= u; result_is_ok = ((u == local_uint_type("87097824890894800794165901619444858655697206439408401342159325362433799963465833258779670963327549206446903807622196074763642894114359201905739606775078813946074899053317297580134329929871847646073758894343134833829668015151562808541626917661957374931734536035195944960000000000000000000000000000000000000000000000")) && result_is_ok); } // Test a very simple constexpr example. { constexpr local_uint_type cu { "123" }; constexpr bool result_cu_is_ok = (cu == 123U); // NOLINT(cppcoreguidelines-avoid-magic-numbers,readability-magic-numbers) result_is_ok = (result_cu_is_ok && result_is_ok); static_assert(result_cu_is_ok, "Error: test_uintwide_t_boost_backend not OK!"); } return result_is_ok; } #if (BOOST_VERSION < 108000) #if ((defined(__clang__) && (__clang_major__ > 9)) && !defined(__APPLE__)) #pragma GCC diagnostic pop #endif #endif #if (defined(__GNUC__) && !defined(__clang__) && (__GNUC__ >= 12)) #pragma GCC diagnostic pop #endif #if (BOOST_VERSION < 108000) #if defined(__GNUC__) #pragma GCC diagnostic pop #pragma GCC diagnostic pop #pragma GCC diagnostic pop #endif #endif #if (((BOOST_VERSION == 108000) || (BOOST_VERSION == 108100)) && defined(BOOST_NO_EXCEPTIONS)) #if defined(__clang__) #pragma GCC diagnostic pop #endif #if defined(_MSC_VER) #pragma warning(pop) #endif #endif ================================================ FILE: test/test_uintwide_t_boost_backend_via_test_arithmetic.cpp ================================================ /////////////////////////////////////////////////////////////// // Copyright 2022 - 2025 Christopher Kormanyos. // Distributed under the Boost // Software License, Version 1.0. (See accompanying file // LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt #include #if !defined(BOOST_VERSION) #error BOOST_VERSION is not defined. Ensure that is properly included. #endif #if ((BOOST_VERSION >= 107900) && !defined(BOOST_MP_STANDALONE)) #define BOOST_MP_STANDALONE #endif #if ((BOOST_VERSION >= 108000) && !defined(BOOST_NO_EXCEPTIONS)) #define BOOST_NO_EXCEPTIONS #endif #if (BOOST_VERSION < 108000) #if defined(__GNUC__) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wconversion" #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wsign-conversion" #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wunused-parameter" #endif #endif #if (defined(__GNUC__) && !defined(__clang__) && (__GNUC__ >= 12)) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wrestrict" #endif #if (BOOST_VERSION < 108000) #if ((defined(__clang__) && (__clang_major__ > 9)) && !defined(__APPLE__)) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wdeprecated-copy" #endif #endif #include #include #include #include // cd /mnt/c/Users/ckorm/Documents/Ks/PC_Software/NumericalPrograms/ExtendedNumberTypes/wide_integer // g++ -march=native -mtune=native -O2 -Wall -Wextra -Wpedantic -Wconversion -Wsign-conversion -Wshadow -std=c++20 -I. -I/mnt/c/boost/boost_1_90_0 test/test_uintwide_t_boost_backend_via_test_arithmetic.cpp -o test_uintwide_t_boost_backend_via_test_arithmetic.exe // ./test_uintwide_t_boost_backend_via_test_arithmetic.exe auto main() -> int { #if defined(WIDE_INTEGER_NAMESPACE) using local_size_type = WIDE_INTEGER_NAMESPACE::math::wide_integer::size_t; #else using local_size_type = ::math::wide_integer::size_t; #endif using local_big_uint_backend_type = ::boost::multiprecision::uintwide_t_backend>; using local_big_uint_type = ::boost::multiprecision::number; test(); return boost::report_errors(); } #if (BOOST_VERSION < 108000) #if ((defined(__clang__) && (__clang_major__ > 9)) && !defined(__APPLE__)) #pragma GCC diagnostic pop #endif #endif #if (defined(__GNUC__) && !defined(__clang__) && (__GNUC__ >= 12)) #pragma GCC diagnostic pop #endif #if (BOOST_VERSION < 108000) #if defined(__GNUC__) #pragma GCC diagnostic pop #pragma GCC diagnostic pop #pragma GCC diagnostic pop #endif #endif ================================================ FILE: test/test_uintwide_t_edge_cases.cpp ================================================ /////////////////////////////////////////////////////////////////////////////// // Copyright Christopher Kormanyos 2019 - 2025. // Distributed under the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt // or copy at http://www.boost.org/LICENSE_1_0.txt) // #include #include #include #include #if !defined(BOOST_VERSION) #error BOOST_VERSION is not defined. Ensure that is properly included. #endif #if ((BOOST_VERSION >= 107900) && !defined(BOOST_MP_STANDALONE)) #define BOOST_MP_STANDALONE #endif #if ((BOOST_VERSION >= 108000) && !defined(BOOST_NO_EXCEPTIONS)) #define BOOST_NO_EXCEPTIONS #endif #if (((BOOST_VERSION == 108000) || (BOOST_VERSION == 108100)) && defined(BOOST_NO_EXCEPTIONS)) #if defined(__clang__) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wsometimes-uninitialized" #endif #if defined(_MSC_VER) #pragma warning(push) #pragma warning(disable : 4701) #endif #endif #if defined(__GNUC__) #if (BOOST_VERSION < 108000) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wconversion" #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wsign-conversion" #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wunused-parameter" #else #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wconversion" #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wsign-conversion" #endif #endif #if (defined(__GNUC__) && !defined(__clang__) && (__GNUC__ >= 12)) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wrestrict" #endif #if (BOOST_VERSION < 108000) #if ((defined(__clang__) && (__clang_major__ > 9)) && !defined(__APPLE__)) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wdeprecated-copy" #endif #endif #include #include #include #include #include #if defined(__clang__) #if defined __has_feature && __has_feature(thread_sanitizer) #define UINTWIDE_T_REDUCE_TEST_DEPTH #endif #elif defined(__GNUC__) #if defined(__SANITIZE_THREAD__) || defined(WIDE_INTEGER_HAS_COVERAGE) #define UINTWIDE_T_REDUCE_TEST_DEPTH #endif #elif defined(_MSC_VER) #if defined(_DEBUG) #define UINTWIDE_T_REDUCE_TEST_DEPTH #endif #endif auto local_inf_f () -> float; auto local_inf_d () -> double; auto local_inf_ld() -> long double; namespace test_uintwide_t_edge { namespace local_edge_cases { #if !defined(UINTWIDE_T_REDUCE_TEST_DEPTH) constexpr auto local_digits2 = static_cast(UINT16_C(16384)); #endif constexpr auto local_digits2_tiny = static_cast(UINT8_C(64)); constexpr auto local_digits2_small = static_cast(UINT16_C(256)); constexpr auto local_digits2_half = static_cast(UINT16_C(128)); } // namespace local_edge_cases #if !defined(UINTWIDE_T_REDUCE_TEST_DEPTH) constexpr auto loop_count_lo = static_cast(UINT16_C(64)); constexpr auto loop_count_hi = static_cast(UINT16_C(256)); #else constexpr auto loop_count_lo = static_cast(UINT16_C(4)); constexpr auto loop_count_hi = static_cast(UINT16_C(8)); #endif #if defined(WIDE_INTEGER_NAMESPACE) using local_uintwide_t_tiny_unsigned_type = WIDE_INTEGER_NAMESPACE::math::wide_integer::uintwide_t; using local_uintwide_t_small_unsigned_type = WIDE_INTEGER_NAMESPACE::math::wide_integer::uintwide_t; using local_uintwide_t_half_unsigned_type = WIDE_INTEGER_NAMESPACE::math::wide_integer::uintwide_t; using local_uintwide_t_half_signed_type = WIDE_INTEGER_NAMESPACE::math::wide_integer::uintwide_t; #else using local_uintwide_t_tiny_unsigned_type = ::math::wide_integer::uintwide_t; using local_uintwide_t_small_unsigned_type = ::math::wide_integer::uintwide_t; using local_uintwide_t_half_unsigned_type = ::math::wide_integer::uintwide_t; using local_uintwide_t_half_signed_type = ::math::wide_integer::uintwide_t; #endif #if defined(WIDE_INTEGER_NAMESPACE) using local_uintwide_t_small_signed_type = WIDE_INTEGER_NAMESPACE::math::wide_integer::uintwide_t; #else using local_uintwide_t_small_signed_type = ::math::wide_integer::uintwide_t; #endif #if !defined(UINTWIDE_T_REDUCE_TEST_DEPTH) using local_uint_backend_type = boost::multiprecision::uintwide_t_backend>; using boost_uint_backend_allocator_type = void; using boost_uint_backend_type = boost::multiprecision::cpp_int_backend; using local_uint_type = boost::multiprecision::number; using boost_uint_type = boost::multiprecision::number; #endif } // namespace test_uintwide_t_edge // LCOV_EXCL_START #if (defined(__cpp_lib_to_chars) && (__cpp_lib_to_chars >= 201611L)) constexpr auto constexpr_test_from_chars() -> ::test_uintwide_t_edge::local_uintwide_t_small_signed_type { const char str_oct[] = "03065217317131113762053502330331263237375335355677425522565630540315656637703556251373"; // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays) ::test_uintwide_t_edge::local_uintwide_t_small_signed_type val { }; using std::from_chars; const auto fc_result = from_chars ( str_oct + static_cast(UINT8_C(1)), // NOLINT(cppcoreguidelines-pro-bounds-array-to-pointer-decay,hicpp-no-array-decay,cppcoreguidelines-pro-bounds-pointer-arithmetic) str_oct + static_cast(sizeof(str_oct) - static_cast(UINT8_C(1))), // NOLINT(cppcoreguidelines-pro-bounds-array-to-pointer-decay,hicpp-no-array-decay,cppcoreguidelines-pro-bounds-pointer-arithmetic) val, 8 ); static_cast(fc_result); return val; } #endif // LCOV_EXCL_STOP namespace test_uintwide_t_edge { enum class local_base // NOLINT(performance-enum-size) { dec, hex, oct }; using eng_sgn_type = std::ranlux24; using eng_dig_type = std::ranlux48; using eng_flt_type = eng_dig_type; auto dist_sgn () -> std::uniform_int_distribution&; auto dist_dig_dec() -> std::uniform_int_distribution&; auto dist_dig_hex() -> std::uniform_int_distribution&; auto dist_dig_oct() -> std::uniform_int_distribution&; auto eng_sgn() -> eng_sgn_type&; auto eng_dig() -> eng_dig_type&; auto eng_flt() -> eng_flt_type&; auto dist_sgn () -> std::uniform_int_distribution& { static std::uniform_int_distribution instance(UINT32_C(0), UINT32_C(1)); return instance; } // NOLINT(cert-err58-cpp,cppcoreguidelines-avoid-non-const-global-variables) auto dist_dig_dec() -> std::uniform_int_distribution& { static std::uniform_int_distribution instance(UINT32_C(1), UINT32_C(9)); return instance; } // NOLINT(cert-err58-cpp,cppcoreguidelines-avoid-non-const-global-variables) auto dist_dig_hex() -> std::uniform_int_distribution& { static std::uniform_int_distribution instance(UINT32_C(1), UINT32_C(15)); return instance; } // NOLINT(cert-err58-cpp,cppcoreguidelines-avoid-non-const-global-variables) auto dist_dig_oct() -> std::uniform_int_distribution& { static std::uniform_int_distribution instance(UINT32_C(1), UINT32_C(7)); return instance; } // NOLINT(cert-err58-cpp,cppcoreguidelines-avoid-non-const-global-variables) auto eng_sgn() -> eng_sgn_type& { static eng_sgn_type instance { }; return instance; } // NOLINT(cert-msc32-c,cert-msc51-cpp,cert-err58-cpp,cppcoreguidelines-avoid-non-const-global-variables) auto eng_dig() -> eng_dig_type& { static eng_dig_type instance { }; return instance; } // NOLINT(cert-msc32-c,cert-msc51-cpp,cert-err58-cpp,cppcoreguidelines-avoid-non-const-global-variables) auto eng_flt() -> eng_flt_type& { static eng_flt_type instance { }; return instance; } // NOLINT(cert-msc32-c,cert-msc51-cpp,cert-err58-cpp,cppcoreguidelines-avoid-non-const-global-variables) auto zero_as_limb () -> const typename local_uintwide_t_small_unsigned_type::limb_type&; auto zero_as_small_unsigned_type() -> const local_uintwide_t_small_unsigned_type&; auto one_as_small_unsigned_type () -> const local_uintwide_t_small_unsigned_type&; auto m_one_as_small_signed_type () -> const local_uintwide_t_small_signed_type&; template auto generate_wide_integer_value(bool is_positive = true, local_base base_to_get = local_base::dec, int digits_in_base_to_get = std::numeric_limits::digits10) -> IntegralTypeWithStringConstruction { using local_integral_type = IntegralTypeWithStringConstruction; static_assert( ( std::numeric_limits::is_signed && std::numeric_limits::digits > static_cast(INT8_C(63))) || ((!std::numeric_limits::is_signed) && std::numeric_limits::digits > static_cast(INT8_C(64))), "Error: Integral type destination does not have enough digits10"); std::string str_x(static_cast(digits_in_base_to_get), '0'); std::generate(str_x.begin(), str_x.end(), [&base_to_get]() // NOLINT(modernize-use-trailing-return-type,-warnings-as-errors) { char c { }; auto& my_dist_dig_oct = dist_dig_oct(); auto& my_dist_dig_dec = dist_dig_dec(); auto& my_dist_dig_hex = dist_dig_hex(); auto& my_eng_dig = eng_dig(); if(base_to_get == local_base::oct) { c = static_cast(my_dist_dig_oct(my_eng_dig)); c = static_cast(c + '0'); } else if(base_to_get == local_base::hex) { c = static_cast(my_dist_dig_hex(my_eng_dig)); if(c < static_cast(INT8_C(10))) { c = static_cast(c + '0'); } else { c = static_cast ( static_cast(c + 'A') - static_cast(INT8_C(10)) ); } } else { c = static_cast(my_dist_dig_dec(my_eng_dig)); c = static_cast(c + static_cast(INT8_C(0x30))); } return c; }); if(base_to_get == local_base::oct) { str_x.insert(str_x.begin(), static_cast(UINT8_C(1)), '0'); } else if(base_to_get == local_base::hex) { str_x.insert(str_x.begin(), static_cast(UINT8_C(1)), 'x'); str_x.insert(str_x.begin(), static_cast(UINT8_C(1)), '0'); } if(base_to_get == local_base::dec) { auto& my_dist_sgn = dist_sgn(); auto& my_eng_sgn = eng_sgn(); // Insert either a positive sign or a negative sign // (always one or the other) depending on the sign of x. char sign_char_to_insert { '+' }; if((!is_positive) && (my_dist_sgn(my_eng_sgn) == std::uint32_t { UINT8_C(0) })) { sign_char_to_insert = '-'; } str_x.insert(str_x.begin(), static_cast(UINT8_C(1)), sign_char_to_insert); } return local_integral_type(str_x.c_str()); } #if !defined(UINTWIDE_T_REDUCE_TEST_DEPTH) auto test_various_edge_operations() -> bool; auto test_various_edge_operations() -> bool { const auto u_max_local = (std::numeric_limits::max)(); const auto u_max_boost = (std::numeric_limits::max)(); local_uint_type result_local; boost_uint_type result_boost; result_local = u_max_local * u_max_local; result_boost = u_max_boost * u_max_boost; const auto result01_is_ok = ((result_local == local_uint_type(static_cast(UINT8_C(1)))) && (result_boost == boost_uint_type(static_cast(UINT8_C(1))))); result_local = (u_max_local - 1U) * u_max_local; result_boost = (u_max_boost - 1U) * u_max_boost; const auto result02_is_ok = ((result_local == local_uint_type(static_cast(UINT8_C(2)))) && (result_boost == boost_uint_type(static_cast(UINT8_C(2))))); const std::string str_seven_and_effs = "0x7" + std::string(static_cast((local_edge_cases::local_digits2 / 4) - static_cast(UINT8_C(1))), 'F'); const local_uint_type u_seven_and_effs_local(str_seven_and_effs.c_str()); const boost_uint_type u_seven_and_effs_boost(str_seven_and_effs.c_str()); result_local = u_seven_and_effs_local * u_seven_and_effs_local; result_boost = u_seven_and_effs_boost * u_seven_and_effs_boost; const auto result03_is_ok = (result_local.convert_to() == result_boost.convert_to()); const std::string str_three_quarter_effs_and_zeros = "0x" + std::string(static_cast((local_edge_cases::local_digits2 / 4) * static_cast(UINT8_C(3))), 'F') + std::string(static_cast((local_edge_cases::local_digits2 / 4) * static_cast(UINT8_C(1))), '0') ; const local_uint_type u_three_quarter_effs_and_zeros_local(str_three_quarter_effs_and_zeros.c_str()); const boost_uint_type u_three_quarter_effs_and_zeros_boost(str_three_quarter_effs_and_zeros.c_str()); result_local = u_three_quarter_effs_and_zeros_local * u_three_quarter_effs_and_zeros_local; result_boost = u_three_quarter_effs_and_zeros_boost * u_three_quarter_effs_and_zeros_boost; const auto result04_is_ok = (result_local.convert_to() == result_boost.convert_to()); const std::string str_one_quarter_effs_and_zeros = "0x" + std::string(static_cast((local_edge_cases::local_digits2 / 4) * static_cast(UINT8_C(1))), 'F') + std::string(static_cast((local_edge_cases::local_digits2 / 4) * static_cast(UINT8_C(3))), '0') ; const local_uint_type u_one_quarter_effs_and_zeros_local(str_one_quarter_effs_and_zeros.c_str()); const boost_uint_type u_one_quarter_effs_and_zeros_boost(str_one_quarter_effs_and_zeros.c_str()); result_local = u_one_quarter_effs_and_zeros_local * u_one_quarter_effs_and_zeros_local; result_boost = u_one_quarter_effs_and_zeros_boost * u_one_quarter_effs_and_zeros_boost; const bool result05_is_ok = (result_local.convert_to() == result_boost.convert_to()); const local_uint_type one_limb_effs_prior_to_half_and_zeros_local(local_uint_type(UINT32_C(0xFFFFFFFF)) << ((std::numeric_limits::digits / 2) - 32)); const boost_uint_type one_limb_effs_prior_to_half_and_zeros_boost(boost_uint_type(UINT32_C(0xFFFFFFFF)) << ((std::numeric_limits::digits / 2) - 32)); result_local = one_limb_effs_prior_to_half_and_zeros_local * one_limb_effs_prior_to_half_and_zeros_local; result_boost = one_limb_effs_prior_to_half_and_zeros_boost * one_limb_effs_prior_to_half_and_zeros_boost; const auto result06_is_ok = (result_local.convert_to() == result_boost.convert_to()); const local_uint_type u_mid_local = u_three_quarter_effs_and_zeros_local / static_cast(UINT8_C(2)); const boost_uint_type u_mid_boost = u_three_quarter_effs_and_zeros_boost / static_cast::value_type>(UINT8_C(2)); constexpr auto signed_shift_amount = static_cast ( -(std::numeric_limits::digits + 7) ); result_local = u_mid_local; result_local.backend().representation() >>= signed_shift_amount; result_boost = u_mid_boost * (boost_uint_type(1U) << (-signed_shift_amount)); const auto result07_is_ok = (result_local.convert_to() == result_boost.convert_to()); result_local = u_mid_local; result_local.backend().representation() <<= signed_shift_amount; result_boost = u_mid_boost / (boost_uint_type(1U) << (-signed_shift_amount)); const auto result08_is_ok = (result_local.convert_to() == result_boost.convert_to()); auto result_is_ok = ( result01_is_ok && result02_is_ok && result03_is_ok && result04_is_ok && result05_is_ok && result06_is_ok && result07_is_ok && result08_is_ok); { using local_derived_uint_type = typename local_uint_type::backend_type::representation_type; using local_limb_type = local_derived_uint_type::limb_type; local_derived_uint_type dt(static_cast(INT8_C(-3))); std::fill(dt.representation().begin(), dt.representation().end(), static_cast(UINT8_C(0))); const auto result_fill_with_zero_is_ok = (dt == 0U); result_is_ok = (result_fill_with_zero_is_ok && result_is_ok); std::fill(dt.representation().begin(), dt.representation().end(), (std::numeric_limits::max)()); const auto result_fill_with_effs_is_ok = (dt == (std::numeric_limits::max)()); result_is_ok = (result_fill_with_effs_is_ok && result_is_ok); } return result_is_ok; } #endif auto test_various_ostream_ops() -> bool; auto test_various_ostream_ops() -> bool { auto result_is_ok = true; eng_sgn().seed(util::util_pseudorandom_time_point_seed::value()); eng_dig().seed(util::util_pseudorandom_time_point_seed::value()); { const auto u = local_uintwide_t_small_unsigned_type(static_cast(UINT32_C(29363))); std::stringstream strm; strm << std::dec << std::showbase << std::setw(static_cast(INT8_C(100))) << std::setfill('#') << u; std::string str_ctrl(static_cast(UINT8_C(100)), '#'); str_ctrl.at(static_cast(static_cast(str_ctrl.size() - static_cast(UINT8_C(1))) - static_cast(UINT8_C(4)))) = '2'; str_ctrl.at(static_cast(static_cast(str_ctrl.size() - static_cast(UINT8_C(1))) - static_cast(UINT8_C(3)))) = '9'; str_ctrl.at(static_cast(static_cast(str_ctrl.size() - static_cast(UINT8_C(1))) - static_cast(UINT8_C(2)))) = '3'; str_ctrl.at(static_cast(static_cast(str_ctrl.size() - static_cast(UINT8_C(1))) - static_cast(UINT8_C(1)))) = '6'; str_ctrl.at(static_cast(static_cast(str_ctrl.size() - static_cast(UINT8_C(1))) - static_cast(UINT8_C(0)))) = '3'; const auto result_u_fill_is_ok = (strm.str() == str_ctrl); result_is_ok = (result_u_fill_is_ok && result_is_ok); } { const auto u = local_uintwide_t_small_unsigned_type(static_cast(UINT32_C(41719))); std::stringstream strm; strm << std::hex << std::uppercase << std::showbase << std::setw(static_cast(INT8_C(100))) << std::setfill('#') << u; std::string str_ctrl(static_cast(UINT8_C(100)), '#'); str_ctrl.at(static_cast(static_cast(str_ctrl.size() - static_cast(UINT8_C(1))) - static_cast(UINT8_C(5)))) = '0'; str_ctrl.at(static_cast(static_cast(str_ctrl.size() - static_cast(UINT8_C(1))) - static_cast(UINT8_C(4)))) = 'X'; str_ctrl.at(static_cast(static_cast(str_ctrl.size() - static_cast(UINT8_C(1))) - static_cast(UINT8_C(3)))) = 'A'; str_ctrl.at(static_cast(static_cast(str_ctrl.size() - static_cast(UINT8_C(1))) - static_cast(UINT8_C(2)))) = '2'; str_ctrl.at(static_cast(static_cast(str_ctrl.size() - static_cast(UINT8_C(1))) - static_cast(UINT8_C(1)))) = 'F'; str_ctrl.at(static_cast(static_cast(str_ctrl.size() - static_cast(UINT8_C(1))) - static_cast(UINT8_C(0)))) = '7'; const auto result_u_fill_is_ok = (strm.str() == str_ctrl); result_is_ok = (result_u_fill_is_ok && result_is_ok); } { const auto u = local_uintwide_t_small_unsigned_type(static_cast(UINT32_C(29363))); std::stringstream strm; strm << std::oct << std::uppercase << std::showbase << std::setw(static_cast(INT8_C(100))) << std::setfill('#') << u; std::string str_ctrl(static_cast(UINT8_C(100)), '#'); str_ctrl.at(static_cast(static_cast(str_ctrl.size() - static_cast(UINT8_C(1))) - static_cast(UINT8_C(5)))) = '0'; str_ctrl.at(static_cast(static_cast(str_ctrl.size() - static_cast(UINT8_C(1))) - static_cast(UINT8_C(4)))) = '7'; str_ctrl.at(static_cast(static_cast(str_ctrl.size() - static_cast(UINT8_C(1))) - static_cast(UINT8_C(3)))) = '1'; str_ctrl.at(static_cast(static_cast(str_ctrl.size() - static_cast(UINT8_C(1))) - static_cast(UINT8_C(2)))) = '2'; str_ctrl.at(static_cast(static_cast(str_ctrl.size() - static_cast(UINT8_C(1))) - static_cast(UINT8_C(1)))) = '6'; str_ctrl.at(static_cast(static_cast(str_ctrl.size() - static_cast(UINT8_C(1))) - static_cast(UINT8_C(0)))) = '3'; const auto result_u_fill_is_ok = (strm.str() == str_ctrl); result_is_ok = (result_u_fill_is_ok && result_is_ok); } { const auto z = local_uintwide_t_small_unsigned_type(static_cast(UINT8_C(0))); { std::stringstream strm; strm << std::oct << z; const auto result_zero_print_as_oct_is_ok = (strm.str() == "0"); result_is_ok = (result_zero_print_as_oct_is_ok && result_is_ok); } { std::stringstream strm; strm << std::dec << z; const auto result_zero_print_as_dec_is_ok = (strm.str() == "0"); result_is_ok = (result_zero_print_as_dec_is_ok && result_is_ok); } { std::stringstream strm; strm << std::hex << z; const auto result_zero_print_as_hex_is_ok = (strm.str() == "0"); result_is_ok = (result_zero_print_as_hex_is_ok && result_is_ok); } } for(auto i = static_cast(UINT8_C(0)); i < static_cast(UINT32_C(1024)); ++i) { const auto u = generate_wide_integer_value ( true, local_base::dec, std::numeric_limits::digits10 ); std::stringstream strm; strm << std::dec << u; const local_uintwide_t_small_unsigned_type u_strm(strm.str().c_str()); const auto result_u_is_ok = (u == u_strm); result_is_ok = (result_u_is_ok && result_is_ok); } for(auto i = static_cast(UINT8_C(0)); i < static_cast(UINT32_C(1024)); ++i) { const auto u = generate_wide_integer_value ( true, local_base::hex, std::numeric_limits::digits / 4 ); std::stringstream strm; strm << std::hex << std::showbase << u; const local_uintwide_t_small_unsigned_type u_strm(strm.str().c_str()); const auto result_u_is_ok = (u == u_strm); result_is_ok = (result_u_is_ok && result_is_ok); } for(auto i = static_cast(UINT8_C(0)); i < static_cast(UINT32_C(1024)); ++i) { const auto u = generate_wide_integer_value ( true, local_base::oct, std::numeric_limits::digits / 3 ); std::stringstream strm; strm << std::oct << std::showbase << u; const local_uintwide_t_small_unsigned_type u_strm(strm.str().c_str()); const auto result_u_is_ok = (u == u_strm); result_is_ok = (result_u_is_ok && result_is_ok); } for(auto i = static_cast(UINT8_C(0)); i < static_cast(UINT32_C(1024)); ++i) { const auto n = generate_wide_integer_value ( false, local_base::dec, std::numeric_limits::digits10 ); std::stringstream strm; strm << std::dec << std::showpos << n; const local_uintwide_t_small_signed_type n_strm(strm.str().c_str()); const auto result_n_is_ok = (n == n_strm); result_is_ok = (result_n_is_ok && result_is_ok); } for(auto i = static_cast(UINT8_C(0)); i < static_cast(UINT32_C(1024)); ++i) { const auto n = generate_wide_integer_value ( false, local_base::hex, (std::numeric_limits::digits + 1) / 4 ); std::stringstream strm; strm << std::hex << std::showbase << std::showpos << n; const local_uintwide_t_small_signed_type n_strm(strm.str().c_str()); const auto result_n_is_ok = (n == n_strm); result_is_ok = (result_n_is_ok && result_is_ok); } for(auto i = static_cast(UINT8_C(0)); i < static_cast(UINT32_C(1024)); ++i) { const auto n = generate_wide_integer_value ( false, local_base::oct, (std::numeric_limits::digits + 1) / 3 ); std::stringstream strm; strm << std::oct << std::showbase << std::showpos << n; const local_uintwide_t_small_signed_type n_strm(strm.str().c_str()); const auto result_n_is_ok = (n == n_strm); result_is_ok = (result_n_is_ok && result_is_ok); } { const local_uintwide_t_small_unsigned_type m1("-0x1"); std::stringstream strm; strm << std::hex << m1; const local_uintwide_t_small_unsigned_type m1_from_strm(strm.str().c_str()); const auto result_read_and_round_trip_neg_hex_str_is_ok = ( m1_from_strm == (std::numeric_limits::max)() ); result_is_ok = (result_read_and_round_trip_neg_hex_str_is_ok && result_is_ok); } return result_is_ok; } auto test_ops_n_half_by_n_half() -> bool; auto test_ops_n_half_by_n_half() -> bool { auto result_is_ok = true; for(auto i = static_cast(UINT8_C(0)); i < static_cast(UINT8_C(24)); ++i) { const auto left_half = generate_wide_integer_value ( true, local_base::hex, static_cast ( static_cast(std::numeric_limits::digits / 8) - static_cast(INT8_C(1)) ) ); const auto right_half = generate_wide_integer_value ( true, local_base::hex, static_cast ( static_cast(std::numeric_limits::digits / 8) - static_cast(INT8_C(1)) ) ); const auto prod_half = left_half * right_half; const auto prod_ctrl = local_uintwide_t_small_unsigned_type(left_half) * local_uintwide_t_small_unsigned_type(right_half); const auto result_multiply_is_ok = (local_uintwide_t_small_unsigned_type(prod_half) == prod_ctrl); result_is_ok = (result_multiply_is_ok && result_is_ok); } for(auto i = static_cast(UINT8_C(2)); i < static_cast(UINT8_C(8)); ++i) { const auto x_half = generate_wide_integer_value ( true, local_base::hex, static_cast(INT8_C(4)) ); const auto pow_half = pow(x_half, i); const auto pow_ctrl = pow(local_uintwide_t_small_unsigned_type(x_half), i); const auto result_pow_is_ok = (local_uintwide_t_small_unsigned_type(pow_half) == pow_ctrl); result_is_ok = (result_pow_is_ok && result_is_ok); } for(auto i = static_cast(UINT8_C(0)); i < static_cast(UINT8_C(8)); ++i) { const auto arg_half = generate_wide_integer_value(); const auto zero_half = generate_wide_integer_value() * local_uintwide_t_half_unsigned_type(zero_as_small_unsigned_type()); const auto pow_zero_half = pow(arg_half, zero_half); const auto pow_zero_ctrl = pow(local_uintwide_t_small_unsigned_type(arg_half), local_uintwide_t_small_unsigned_type(zero_half)); const auto result_pow_zero_is_ok = ((local_uintwide_t_small_unsigned_type(pow_zero_half) == pow_zero_ctrl) && (pow_zero_half == 1)); result_is_ok = (result_pow_zero_is_ok && result_is_ok); } for(auto i = static_cast(UINT8_C(3)); i < static_cast(UINT8_C(14)); ++i) { const auto x_half = generate_wide_integer_value(); const auto rootk_half = rootk(x_half, i); const auto rootk_ctrl = rootk(local_uintwide_t_small_unsigned_type(x_half), i); const auto result_rootk_is_ok = (local_uintwide_t_small_unsigned_type(rootk_half) == rootk_ctrl); result_is_ok = (result_rootk_is_ok && result_is_ok); } for(auto i = static_cast(INT8_C(2)); i < static_cast(INT8_C(40)); ++i) { const auto x_half = generate_wide_integer_value(); const auto shr_half = x_half >> i; const auto shr_ctrl = local_uintwide_t_small_unsigned_type(x_half) >> i; const auto result_shr_is_ok = (local_uintwide_t_small_unsigned_type(shr_half) == shr_ctrl); result_is_ok = (result_shr_is_ok && result_is_ok); } for(auto i = static_cast(INT16_C(1002)); i < static_cast(INT16_C(1012)); ++i) { const auto x_half = generate_wide_integer_value(); const auto shr_half = x_half >> i; const auto shr_ctrl = local_uintwide_t_small_unsigned_type(x_half) >> i; const auto result_shr_is_ok = ((local_uintwide_t_small_unsigned_type(shr_half) == shr_ctrl) && (shr_half == 0)); result_is_ok = (result_shr_is_ok && result_is_ok); } for(auto i = static_cast(UINT8_C(0)); i < static_cast(UINT8_C(24)); ++i) { const auto left_half = generate_wide_integer_value(); const auto right_half = generate_wide_integer_value(); const auto xor_half = left_half ^ right_half; const auto xor_ctrl = ( local_uintwide_t_small_unsigned_type(left_half) ^ local_uintwide_t_small_unsigned_type(right_half)); const auto result_xor_is_ok = (local_uintwide_t_small_unsigned_type(xor_half) == xor_ctrl); result_is_ok = (result_xor_is_ok && result_is_ok); } for(auto i = static_cast(UINT8_C(0)); i < static_cast(UINT8_C(32)); ++i) { const auto left_half = generate_wide_integer_value(); const auto right_half = generate_wide_integer_value(); const auto gcd_half = gcd(left_half, right_half); const auto gcd_ctrl = gcd(local_uintwide_t_small_unsigned_type(left_half), local_uintwide_t_small_unsigned_type(right_half)); const auto result_gcd_is_ok = (local_uintwide_t_small_unsigned_type(gcd_half) == gcd_ctrl); result_is_ok = (result_gcd_is_ok && result_is_ok); } for(auto i = static_cast(UINT8_C(0)); i < static_cast(UINT8_C(32)); ++i) { const auto x_half_signed = generate_wide_integer_value ( false, local_base::dec, static_cast(std::numeric_limits::digits10 - 7) ); const auto x_small_unsigned = local_uintwide_t_small_unsigned_type(x_half_signed); const auto x_ctrl_signed = static_cast(x_small_unsigned); const auto result_convert_is_ok = (x_half_signed == x_ctrl_signed); result_is_ok = (result_convert_is_ok && result_is_ok); } return result_is_ok; } auto test_various_roots_and_pow_etc() -> bool; auto test_various_roots_and_pow_etc() -> bool { auto result_is_ok = true; const auto ten_pow_forty = local_uintwide_t_small_unsigned_type("10000000000000000000000000000000000000000"); { const auto u_root = rootk(ten_pow_forty, static_cast(UINT8_C(1))); const auto result_u_root_is_ok = (u_root == ten_pow_forty); result_is_ok = (result_u_root_is_ok && result_is_ok); } { const auto u_root = rootk(ten_pow_forty, static_cast(UINT8_C(2))); const auto ten_pow_twenty = local_uintwide_t_small_unsigned_type("100000000000000000000"); const auto result_u_root_is_ok = ( (u_root == ten_pow_twenty) && (u_root == sqrt(ten_pow_forty))); result_is_ok = (result_u_root_is_ok && result_is_ok); } { const auto ten_pow_thirty_nine = ten_pow_forty / 10; const auto u_root = rootk(ten_pow_thirty_nine, static_cast(UINT8_C(3))); const auto ten_pow_thirteen = local_uintwide_t_small_unsigned_type(static_cast(UINT64_C(10000000000000))); const auto result_u_root_is_ok = (u_root == ten_pow_thirteen); result_is_ok = (result_u_root_is_ok && result_is_ok); } { const auto& u = zero_as_small_unsigned_type(); const auto u_root = sqrt(u); const auto result_sqrt_zero_is_ok = (u_root == 0U); result_is_ok = (result_sqrt_zero_is_ok && result_is_ok); } { const auto& u = zero_as_small_unsigned_type(); const auto u_root = cbrt(u); const auto result_cbrt_zero_is_ok = (u_root == zero_as_small_unsigned_type()); result_is_ok = (result_cbrt_zero_is_ok && result_is_ok); } { const auto& u = zero_as_small_unsigned_type(); const auto u_root = rootk(u, 7U); const auto result_rootk_zero_is_ok = (u_root == zero_as_small_unsigned_type()); result_is_ok = (result_rootk_zero_is_ok && result_is_ok); } for(auto i = static_cast(UINT8_C(0)); i < static_cast(loop_count_hi); ++i) { auto b_gen = generate_wide_integer_value(); // NOLINT auto m_gen = generate_wide_integer_value(); while(!(b_gen > m_gen)) // NOLINT(altera-id-dependent-backward-branch) { b_gen = generate_wide_integer_value(); m_gen = generate_wide_integer_value(); } const auto powm_zero_result = powm(b_gen, 0U, m_gen); const auto powm_one_result = powm(b_gen, 1U, m_gen); const auto result_powm_checks_are_ok = ( (powm_zero_result == one_as_small_unsigned_type()) && (powm_one_result == (b_gen % m_gen))); result_is_ok = (result_powm_checks_are_ok && result_is_ok); } { using cbrt_data_array_type = std::array(UINT8_C(3))>; const cbrt_data_array_type cbrt_data = { local_uintwide_t_small_unsigned_type("67828177552242475987719934121374621432592443433392865437894564885546642548776"), local_uintwide_t_small_unsigned_type("114688795833607759436755318000801811092546159899778523634298604873518327575437"), local_uintwide_t_small_unsigned_type("97147734462982474181332761989635722126392718381938387792632943975979168194114"), }; const cbrt_data_array_type cbrt_ctrl = { local_uintwide_t_small_unsigned_type("40782143592716585610825381"), local_uintwide_t_small_unsigned_type("48585535929752371864326912"), local_uintwide_t_small_unsigned_type("45970323401457076345923126"), }; auto i = static_cast(UINT8_C(0)); for(const auto& u : cbrt_data) { const auto cbrt_u = cbrt(u); const auto result_cbrt_is_ok = (cbrt_u == cbrt_ctrl[i]); // NOLINT(cppcoreguidelines-pro-bounds-constant-array-index) ++i; result_is_ok = (result_cbrt_is_ok && result_is_ok); } } for(auto i = static_cast(UINT8_C(0)); i < static_cast(loop_count_hi); ++i) { const auto high_bit = static_cast ( local_uintwide_t_small_unsigned_type(1) << (std::numeric_limits::digits - 1) ); const auto u = static_cast ( static_cast ( generate_wide_integer_value() | high_bit ) >> 3U ); const auto sqrt_sqrt_u = sqrt(sqrt(u)); const auto quartic_root_u = rootk(u, 4U); const auto result_quartic_root_is_ok = (sqrt_sqrt_u == quartic_root_u); result_is_ok = (result_quartic_root_is_ok && result_is_ok); } for(auto i = static_cast(UINT8_C(0)); i < static_cast(loop_count_hi); ++i) { const auto b_gen = generate_wide_integer_value(); const auto powm_zero_one_result = powm(b_gen, 0U, one_as_small_unsigned_type()); const auto result_powm_zero_one_is_ok = (powm_zero_one_result == zero_as_small_unsigned_type()); result_is_ok = (result_powm_zero_one_is_ok && result_is_ok); } for(auto i = static_cast(UINT8_C(0)); i < static_cast(loop_count_hi); ++i) { constexpr auto digits10_to_get_b = static_cast ( static_cast(std::numeric_limits::digits10) * 0.45F ); constexpr auto digits10_to_get_m = static_cast ( static_cast(std::numeric_limits::digits10) * 0.55F ); const auto b_gen = generate_wide_integer_value(true, local_base::dec, digits10_to_get_b); const auto m_gen = generate_wide_integer_value(true, local_base::dec, digits10_to_get_m); const auto powm_two_result = powm(b_gen, 2U, m_gen); const auto powm_two_control = static_cast((b_gen * b_gen) % m_gen); const auto result_powm_two_is_ok = (powm_two_result == powm_two_control); result_is_ok = (result_powm_two_is_ok && result_is_ok); } return result_is_ok; } namespace local_edge_cases { using small_integers_array_type = std::array(UINT8_C(50))>; constexpr auto small_integers = small_integers_array_type { 1, 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227 }; } // namespace local_edge_cases auto test_small_prime_and_non_prime() -> bool; auto test_small_prime_and_non_prime() -> bool { constexpr auto local_my_width2 = local_uintwide_t_small_unsigned_type::my_width2; using local_limb_type = typename local_uintwide_t_small_unsigned_type::limb_type; #if defined(WIDE_INTEGER_NAMESPACE) using local_distribution_type = WIDE_INTEGER_NAMESPACE::math::wide_integer::uniform_int_distribution; #else using local_distribution_type = ::math::wide_integer::uniform_int_distribution; #endif using random_engine_type = std::minstd_rand; local_distribution_type distribution; using local_random_engine_result_type = typename random_engine_type::result_type; auto generator = random_engine_type(util::util_pseudorandom_time_point_seed::value()); random_engine_type local_generator(generator); auto result_is_ok = true; auto result_p_is_prime_is_ok = true; for(auto ip = static_cast(UINT8_C(1)); ip < local_edge_cases::small_integers.size(); ++ip) { const auto p_is_prime = miller_rabin ( static_cast(local_edge_cases::small_integers[ip]), // NOLINT(cppcoreguidelines-pro-bounds-constant-array-index) 25U, distribution, local_generator ); result_p_is_prime_is_ok = (p_is_prime && result_p_is_prime_is_ok); } const auto result_one_is_prime = miller_rabin ( static_cast(local_edge_cases::small_integers.front()), 25U, distribution, local_generator ); const auto result_one_is_not_prime_is_ok = (!result_one_is_prime); result_is_ok = (result_one_is_not_prime_is_ok && result_is_ok); const auto not_prime_checker = [&distribution, &local_generator](const std::size_t first, const std::size_t last_inclusive) { auto result_small_n_is_not_prime_is_ok = true; local_uintwide_t_small_unsigned_type prime_candidate = local_edge_cases::small_integers[first]; // NOLINT(cppcoreguidelines-pro-bounds-constant-array-index) for(auto ip = static_cast(first + static_cast(UINT8_C(1))); ip <= last_inclusive; ++ip) // NOLINT(altera-id-dependent-backward-branch) { prime_candidate *= local_edge_cases::small_integers[ip]; // NOLINT(cppcoreguidelines-pro-bounds-constant-array-index) const auto result_small_n_is_prime = miller_rabin(prime_candidate, 25U, distribution, local_generator); result_small_n_is_not_prime_is_ok = ((!result_small_n_is_prime) && result_small_n_is_not_prime_is_ok); } return result_small_n_is_not_prime_is_ok; }; { // Exclude small prime factors from { 3 ... 53 }. // Product[Prime[i], {i, 2, 16}] = 16294579238595022365 const auto result_not_prime_checker_is_ok = not_prime_checker ( static_cast(UINT8_C(2)), static_cast(UINT8_C(16)) ); result_is_ok = (result_not_prime_checker_is_ok && result_is_ok); } { // Exclude small prime factors from { 59 ... 101 }. // Product[Prime[i], {i, 17, 26}] = 7145393598349078859 const auto result_not_prime_checker_is_ok = not_prime_checker ( static_cast(UINT8_C(17)), static_cast(UINT8_C(26)) ); result_is_ok = (result_not_prime_checker_is_ok && result_is_ok); } { // Exclude small prime factors from { 103 ... 149 }. // Product[Prime[i], {i, 27, 35}] = 6408001374760705163 const auto result_not_prime_checker_is_ok = not_prime_checker ( static_cast(UINT8_C(27)), static_cast(UINT8_C(35)) ); result_is_ok = (result_not_prime_checker_is_ok && result_is_ok); } { // Exclude small prime factors from { 151 ... 191 }. // Product[Prime[i], {i, 36, 43}] = 690862709424854779 const auto result_not_prime_checker_is_ok = not_prime_checker ( static_cast(UINT8_C(36)), static_cast(UINT8_C(43)) ); result_is_ok = (result_not_prime_checker_is_ok && result_is_ok); } { // Exclude small prime factors from { 193 ... 227 }. // Product[Prime[i], {i, 44, 49}] = 80814592450549 const auto result_not_prime_checker_is_ok = not_prime_checker ( static_cast(UINT8_C(44)), static_cast(UINT8_C(49)) ); result_is_ok = (result_not_prime_checker_is_ok && result_is_ok); } return result_is_ok; } auto test_some_gcd_and_equal_left_right() -> bool; auto test_some_gcd_and_equal_left_right() -> bool { auto result_is_ok = true; for(auto i = static_cast(UINT8_C(0)); i < static_cast(UINT32_C(64)); ++i) { auto result_gcd_is_ok = true; const auto left = generate_wide_integer_value ( true, local_base::dec, static_cast(std::numeric_limits::digits10 - static_cast(INT8_C(1))) ); const auto& right = left; { const auto result_gcd_left_equal_right_is_ok = ((left == right) && (gcd(left, right) == left)); result_gcd_is_ok = (result_gcd_left_equal_right_is_ok && result_gcd_is_ok); } { const auto u_left = left + static_cast(UINT8_C(1)); const auto& v_right = right; const auto result_gcd_left_unequal_right_is_ok = ((u_left != v_right) && (gcd(u_left, v_right) != u_left)); result_gcd_is_ok = (result_gcd_left_unequal_right_is_ok && result_gcd_is_ok); } result_is_ok = (result_gcd_is_ok && result_is_ok); } const auto gcd64_equal_checker = [](const std::size_t first, const std::size_t last_inclusive, const std::uint64_t right) // NOLINT(bugprone-easily-swappable-parameters) { #if defined(WIDE_INTEGER_NAMESPACE) using WIDE_INTEGER_NAMESPACE::math::wide_integer::gcd; #else using ::math::wide_integer::gcd; #endif auto left = static_cast(local_edge_cases::small_integers[first]); // NOLINT(cppcoreguidelines-pro-bounds-constant-array-index) for(auto ig = static_cast(first + static_cast(UINT8_C(1))); ig <= last_inclusive; ++ig) // NOLINT(altera-id-dependent-backward-branch) { left *= static_cast(local_edge_cases::small_integers[ig]); // NOLINT(cppcoreguidelines-pro-bounds-constant-array-index) } const auto result_gcd_left_equal_right_is_ok = ((left == right) && (gcd(left, right) == left)); return result_gcd_left_equal_right_is_ok; }; { // Consider small prime factors from { 3 ... 53 }. // Product[Prime[i], {i, 2, 16}] = 16294579238595022365 const auto result_gcd64_equal_checker_is_ok = gcd64_equal_checker ( static_cast(UINT8_C(2)), static_cast(UINT8_C(16)), static_cast(UINT64_C(16294579238595022365)) ); result_is_ok = (result_gcd64_equal_checker_is_ok && result_is_ok); } { // Consider small prime factors from { 59 ... 101 }. // Product[Prime[i], {i, 17, 26}] = 7145393598349078859 const auto result_gcd64_equal_checker_is_ok = gcd64_equal_checker ( static_cast(UINT8_C(17)), static_cast(UINT8_C(26)), static_cast(UINT64_C(7145393598349078859)) ); result_is_ok = (result_gcd64_equal_checker_is_ok && result_is_ok); } { // Consider small prime factors from { 103 ... 149 }. // Product[Prime[i], {i, 27, 35}] = 6408001374760705163 const auto result_gcd64_equal_checker_is_ok = gcd64_equal_checker ( static_cast(UINT8_C(27)), static_cast(UINT8_C(35)), static_cast(UINT64_C(6408001374760705163)) ); result_is_ok = (result_gcd64_equal_checker_is_ok && result_is_ok); } { // Consider small prime factors from { 151 ... 191 }. // Product[Prime[i], {i, 36, 43}] = 690862709424854779 const auto result_gcd64_equal_checker_is_ok = gcd64_equal_checker ( static_cast(UINT8_C(36)), static_cast(UINT8_C(43)), static_cast(UINT64_C(690862709424854779)) ); result_is_ok = (result_gcd64_equal_checker_is_ok && result_is_ok); } { // Consider small prime factors from { 193 ... 227 }. // Product[Prime[i], {i, 44, 49}] = 80814592450549 const auto result_gcd64_equal_checker_is_ok = gcd64_equal_checker ( static_cast(UINT8_C(44)), static_cast(UINT8_C(49)), static_cast(UINT64_C(80814592450549)) ); result_is_ok = (result_gcd64_equal_checker_is_ok && result_is_ok); } { #if defined(WIDE_INTEGER_NAMESPACE) using WIDE_INTEGER_NAMESPACE::math::wide_integer::gcd; #else using ::math::wide_integer::gcd; #endif // GCD[6170895419598858564, 1073014744210933590] // 594 const auto gcd64 = gcd(static_cast(UINT64_C(6170895419598858564)), static_cast(UINT64_C(1073014744210933590))); const auto result_gcd64_is_ok = (gcd64 == static_cast(UINT64_C(594))); result_is_ok = (result_gcd64_is_ok && result_is_ok); } { // GCD[20769612331917304, 11556552886528217295] // 6673 #if defined(WIDE_INTEGER_NAMESPACE) using WIDE_INTEGER_NAMESPACE::math::wide_integer::gcd; #else using ::math::wide_integer::gcd; #endif const auto gcd64 = gcd(static_cast(UINT64_C(20769612331917304)), static_cast(UINT64_C(11556552886528217295))); const auto result_gcd64_is_ok = (gcd64 == static_cast(UINT64_C(6673))); result_is_ok = (result_gcd64_is_ok && result_is_ok); } { // GCD[3263830144632800334, 9189394046487653520] // 56598 #if defined(WIDE_INTEGER_NAMESPACE) using WIDE_INTEGER_NAMESPACE::math::wide_integer::gcd; #else using ::math::wide_integer::gcd; #endif const auto gcd64 = gcd(static_cast(UINT64_C(3263830144632800334)), static_cast(UINT64_C(9189394046487653520))); const auto result_gcd64_is_ok = (gcd64 == static_cast(UINT64_C(56598))); result_is_ok = (result_gcd64_is_ok && result_is_ok); } { // GCD[7515843862511910988, 11558893357905095758] // 420278 #if defined(WIDE_INTEGER_NAMESPACE) using WIDE_INTEGER_NAMESPACE::math::wide_integer::gcd; #else using ::math::wide_integer::gcd; #endif const auto gcd64 = gcd(static_cast(UINT64_C(7515843862511910988)), static_cast(UINT64_C(11558893357905095758))); const auto result_gcd64_is_ok = (gcd64 == static_cast(UINT64_C(420278))); result_is_ok = (result_gcd64_is_ok && result_is_ok); } { #if defined(WIDE_INTEGER_NAMESPACE) using WIDE_INTEGER_NAMESPACE::math::wide_integer::gcd; #else using ::math::wide_integer::gcd; #endif const auto result_gcd_left_zero = gcd(static_cast(UINT64_C(7515843862511910988)), static_cast(UINT64_C(0))); const auto result_gcd_left_zero_is_ok = (result_gcd_left_zero == static_cast(UINT64_C(7515843862511910988))); result_is_ok = (result_gcd_left_zero_is_ok && result_is_ok); } { #if defined(WIDE_INTEGER_NAMESPACE) using WIDE_INTEGER_NAMESPACE::math::wide_integer::gcd; #else using ::math::wide_integer::gcd; #endif const auto result_gcd_right_zero = gcd(static_cast(UINT64_C(0)), static_cast(UINT64_C(7515843862511910988))); const auto result_gcd_right_zero_is_ok = (result_gcd_right_zero == static_cast(UINT64_C(7515843862511910988))); result_is_ok = (result_gcd_right_zero_is_ok && result_is_ok); } return result_is_ok; } auto test_various_isolated_edge_cases() -> bool // NOLINT(readability-function-cognitive-complexity) { auto result_is_ok = true; { // See also bug report in legacy project long_long_long // https://github.com/ckormanyos/long_long_long/issues/11 using local_uint64_type = local_uintwide_t_tiny_unsigned_type; using local_ctrl64_type = std::uint64_t; constexpr std::size_t max_size { static_cast ( std::numeric_limits::digits / 8 ) }; std::array buffer { 0x00U, 0x00U, 0x00U, 0x04U, 0x00U, 0x00U, 0x00U, 0xFFU, // NOLINT(cppcoreguidelines-avoid-magic-numbers,readability-magic-numbers) 0x0FU, 0x00U, 0x00U, 0x00U, 0x00U, 0x03U, 0x00U, 0x00U // NOLINT(cppcoreguidelines-avoid-magic-numbers,readability-magic-numbers) }; auto load_uint64_t { [](const std::uint8_t* p_first) { return std::uint64_t { *(p_first + std::size_t { UINT8_C(0) }) } << unsigned { UINT8_C(0) } // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) | std::uint64_t { *(p_first + std::size_t { UINT8_C(1) }) } << unsigned { UINT8_C(8) } // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) | std::uint64_t { *(p_first + std::size_t { UINT8_C(2) }) } << unsigned { UINT8_C(16) } // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) | std::uint64_t { *(p_first + std::size_t { UINT8_C(3) }) } << unsigned { UINT8_C(24) } // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) | std::uint64_t { *(p_first + std::size_t { UINT8_C(4) }) } << unsigned { UINT8_C(32) } // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) | std::uint64_t { *(p_first + std::size_t { UINT8_C(5) }) } << unsigned { UINT8_C(40) } // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) | std::uint64_t { *(p_first + std::size_t { UINT8_C(6) }) } << unsigned { UINT8_C(48) } // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) | std::uint64_t { *(p_first + std::size_t { UINT8_C(7) }) } << unsigned { UINT8_C(56) }; // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) } }; local_uint64_type a_uint { load_uint64_t(buffer.data() + std::size_t { 0U * max_size }) }; // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast) local_uint64_type b_uint { load_uint64_t(buffer.data() + std::size_t { 1U * max_size }) }; // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast) local_ctrl64_type a_ctrl { load_uint64_t(buffer.data() + std::size_t { 0U * max_size }) }; // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast) local_ctrl64_type b_ctrl { load_uint64_t(buffer.data() + std::size_t { 1U * max_size }) }; // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast) if(a_uint < b_uint) { std::swap(a_uint, b_uint); std::swap(a_ctrl, b_ctrl); } const local_uint64_type c_uint = a_uint / b_uint; const local_ctrl64_type c_ctrl = a_ctrl / b_ctrl; const bool result_op_is_ok { (static_cast(c_uint) == c_ctrl) && (UINT64_C(0x000000000054FFFF) == c_ctrl) }; result_is_ok = (result_op_is_ok && result_is_ok); } { using local_rep_type = typename local_uintwide_t_small_unsigned_type::representation_type; using local_value_type = typename local_rep_type::value_type; local_rep_type rep ( local_uintwide_t_small_unsigned_type::number_of_limbs, (std::numeric_limits::max)(), typename local_rep_type::allocator_type() ); const auto rep_as_max_is_ok = (local_uintwide_t_small_unsigned_type(rep) == (std::numeric_limits::max)()); result_is_ok = (rep_as_max_is_ok && result_is_ok); std::fill(rep.begin(), rep.end(), static_cast(UINT8_C(0))); const auto rep_as_zero_is_ok = (local_uintwide_t_small_unsigned_type(rep) == 0); result_is_ok = (rep_as_zero_is_ok && result_is_ok); std::fill(rep.begin(), rep.end(), (std::numeric_limits::max)()); const auto rep_as_max2_is_ok = (local_uintwide_t_small_unsigned_type(rep) == (std::numeric_limits::max)()); result_is_ok = (rep_as_max2_is_ok && result_is_ok); rep = local_rep_type ( static_cast(local_rep_type::size()), (std::numeric_limits::max)(), typename local_rep_type::allocator_type() ); const auto rep_as_max3_is_ok = ( local_uintwide_t_small_unsigned_type(rep) == (std::numeric_limits::max)() ); result_is_ok = (rep_as_max3_is_ok && result_is_ok); } { auto& my_eng_flt = eng_flt(); for(auto i = static_cast(UINT8_C(0)); i < static_cast(UINT8_C(16)); ++i) { my_eng_flt.seed(util::util_pseudorandom_time_point_seed::value()); std::uniform_real_distribution dis { std::uniform_real_distribution { static_cast(1.01L), // NOLINT(cppcoreguidelines-avoid-magic-numbers,readability-magic-numbers) static_cast(1.04L) // NOLINT(cppcoreguidelines-avoid-magic-numbers,readability-magic-numbers) } }; const auto inf_f = ::local_inf_f () * dis(my_eng_flt); const auto inf_d = ::local_inf_d () * static_cast(dis(my_eng_flt)); const auto inf_ld = ::local_inf_ld() * static_cast(dis(my_eng_flt)); local_uintwide_t_small_unsigned_type u_inf_f (inf_f); local_uintwide_t_small_unsigned_type u_inf_d (inf_d); local_uintwide_t_small_unsigned_type u_inf_ld(inf_ld); const auto result_infinities_is_ok = ( (u_inf_f == 0) && (u_inf_d == 0) && (u_inf_ld == 0)); result_is_ok = (result_infinities_is_ok && result_is_ok); } } for(auto i = static_cast(UINT8_C(0)); i < static_cast(loop_count_hi); ++i) { // Verify shift of an unsigned wide-integer by a signed amount. const auto u_gen = generate_wide_integer_value(); const auto ur_neg = u_gen << static_cast(INT8_C(-4)); const auto ur_ctrl = u_gen >> static_cast(UINT8_C(4)); const auto ul_neg = u_gen >> static_cast(INT8_C(-4)); const auto ul_ctrl = u_gen << static_cast(UINT8_C(4)); const auto result_left_is_ok = (ul_neg == ul_ctrl); const auto result_right_is_ok = (ur_neg == ur_ctrl); result_is_ok = (result_left_is_ok && result_right_is_ok && result_is_ok); } for(auto i = static_cast(UINT8_C(0)); i < static_cast(loop_count_hi); ++i) { // Verify shift of a signed wide-integer by a signed amount. const auto s_gen = generate_wide_integer_value(false); const auto sr_neg = s_gen << static_cast(INT8_C(-4)); const auto sr_ctrl = s_gen >> static_cast(UINT8_C(4)); const auto sl_neg = s_gen >> static_cast(INT8_C(-4)); const auto sl_ctrl = s_gen << static_cast(UINT8_C(4)); const auto result_left_is_ok = (sl_neg == sl_ctrl); const auto result_right_is_ok = (sr_neg == sr_ctrl); result_is_ok = (result_left_is_ok && result_right_is_ok && result_is_ok); } { local_uintwide_t_small_unsigned_type u1(static_cast(UINT8_C(1))); u1 /= zero_as_limb(); const auto result_overflow_is_ok = (u1 == (std::numeric_limits::max)()); result_is_ok = (result_overflow_is_ok && result_is_ok); } { local_uintwide_t_small_unsigned_type u1(static_cast(UINT8_C(1))); u1 /= local_uintwide_t_small_unsigned_type(zero_as_limb()); const auto result_overflow_is_ok = (u1 == (std::numeric_limits::max)()); result_is_ok = (result_overflow_is_ok && result_is_ok); } for(auto i = static_cast(UINT8_C(0)); i < static_cast(loop_count_hi); ++i) { // Verify division of finite, unsigned numerator by zero which returns the maximum of the type. auto u_gen = generate_wide_integer_value(); u_gen /= zero_as_small_unsigned_type(); const auto result_unsigned_div_by_zero_is_ok = (u_gen == (std::numeric_limits::max)()); result_is_ok = (result_unsigned_div_by_zero_is_ok && result_is_ok); } for(auto i = static_cast(UINT8_C(0)); i < static_cast(loop_count_hi); ++i) { // Verify division of finite, signed numerator by zero which returns the maximum of the type. const auto u_gen = generate_wide_integer_value(); auto n_gen = local_uintwide_t_small_signed_type(u_gen); n_gen /= local_uintwide_t_small_signed_type(zero_as_small_unsigned_type()); const auto result_signed_div_by_zero_is_ok = (n_gen == (std::numeric_limits::max)()); result_is_ok = (result_signed_div_by_zero_is_ok && result_is_ok); } { // Verify division of zero by zero which returns the maximum of the type. local_uintwide_t_small_unsigned_type z = zero_as_small_unsigned_type(); z /= zero_as_small_unsigned_type(); const auto result_zero_div_by_zero_is_ok = (z == (std::numeric_limits::max)()); result_is_ok = (result_zero_div_by_zero_is_ok && result_is_ok); } for(auto i = static_cast(UINT8_C(0)); i < static_cast(loop_count_hi); ++i) { // Verify modulus of zero with a finite denominator which returns zero modulus. auto u_gen = generate_wide_integer_value(); const auto mod = zero_as_small_unsigned_type() % u_gen; const auto result_zero_mod_with_finite_is_ok = (mod == zero_as_small_unsigned_type()); result_is_ok = (result_zero_mod_with_finite_is_ok && result_is_ok); } { const auto ten_pow_forty = local_uintwide_t_small_unsigned_type("10000000000000000000000000000000000000000"); auto a(ten_pow_forty); const auto b(local_uintwide_t_small_unsigned_type("10000000000000000000000000000000000000000")); const auto& c(a %= b); #if (defined(__clang__) && (defined(__clang_major__) && (__clang_major__ > 6))) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wself-assign-overloaded" #endif const auto& d(a %= a); // NOLINT(clang-diagnostic-self-assign-overloaded) #if (defined(__clang__) && (defined(__clang_major__) && (__clang_major__ > 6))) #pragma GCC diagnostic pop #endif const auto result_self_mod_is_ok = ((c == 0) && (d == 0)); result_is_ok = (result_self_mod_is_ok && result_is_ok); } for(auto i = static_cast(UINT8_C(0)); i < static_cast(loop_count_hi); ++i) { auto shift_amount = // NOLINT(altera-id-dependent-backward-branch) static_cast ( static_cast ( (std::numeric_limits::digits / static_cast(INT8_C(100))) + (((std::numeric_limits::digits % static_cast(INT8_C(100))) != 0) ? 1 : 0) ) * static_cast(INT8_C(100)) ); for( ; shift_amount < static_cast(UINT32_C(2000)); // NOLINT(altera-id-dependent-backward-branch) shift_amount += static_cast(UINT32_C(100))) { const auto u_gen = generate_wide_integer_value(); auto result_overshift_is_ok = true; const auto u_left_n = local_uintwide_t_small_unsigned_type(u_gen) << static_cast (shift_amount); const auto u_left_u = local_uintwide_t_small_unsigned_type(u_gen) << static_cast(shift_amount); const auto u_right_n = local_uintwide_t_small_unsigned_type(u_gen) >> static_cast (shift_amount); const auto u_right_u = local_uintwide_t_small_unsigned_type(u_gen) >> static_cast(shift_amount); result_overshift_is_ok = ((u_left_n == zero_as_small_unsigned_type()) && result_overshift_is_ok); result_overshift_is_ok = ((u_left_u == zero_as_small_unsigned_type()) && result_overshift_is_ok); result_overshift_is_ok = ((u_right_n == zero_as_small_unsigned_type()) && result_overshift_is_ok); result_overshift_is_ok = ((u_right_u == zero_as_small_unsigned_type()) && result_overshift_is_ok); result_is_ok = (result_overshift_is_ok && result_is_ok); } } for(auto i = static_cast(UINT8_C(0)); i < static_cast(loop_count_hi); ++i) { auto shift_amount = static_cast ( ( (std::numeric_limits::digits / 100) // NOLINT(cppcoreguidelines-avoid-magic-numbers,readability-magic-numbers) + (((std::numeric_limits::digits % 100) != 0) ? 1 : 0) // NOLINT(cppcoreguidelines-avoid-magic-numbers,readability-magic-numbers) ) * 100 // NOLINT(cppcoreguidelines-avoid-magic-numbers,readability-magic-numbers) ); for( ; shift_amount < static_cast(UINT32_C(2000)); // NOLINT(altera-id-dependent-backward-branch) shift_amount += static_cast(UINT32_C(100))) { const auto n_gen = generate_wide_integer_value(false); const auto n_is_neg = (n_gen < 0); const auto n_left_n = local_uintwide_t_small_signed_type(n_gen) << static_cast (shift_amount); const auto n_left_u = local_uintwide_t_small_signed_type(n_gen) << static_cast(shift_amount); const auto n_right_n = local_uintwide_t_small_signed_type(n_gen) >> static_cast (shift_amount); const auto n_right_u = local_uintwide_t_small_signed_type(n_gen) >> static_cast(shift_amount); auto result_overshift_is_ok = true; result_overshift_is_ok = ((n_left_n == local_uintwide_t_small_signed_type(zero_as_small_unsigned_type())) && result_overshift_is_ok); result_overshift_is_ok = ((n_left_u == local_uintwide_t_small_signed_type(zero_as_small_unsigned_type())) && result_overshift_is_ok); result_overshift_is_ok = ((n_right_n == ((!n_is_neg) ? local_uintwide_t_small_signed_type(zero_as_small_unsigned_type()) : m_one_as_small_signed_type())) && result_overshift_is_ok); result_overshift_is_ok = ((n_right_u == ((!n_is_neg) ? local_uintwide_t_small_signed_type(zero_as_small_unsigned_type()) : m_one_as_small_signed_type())) && result_overshift_is_ok); result_is_ok = (result_overshift_is_ok && result_is_ok); } } return result_is_ok; } auto test_to_and_from_chars_and_to_string() -> bool; auto test_to_and_from_chars_and_to_string() -> bool // NOLINT(readability-function-cognitive-complexity) { eng_sgn().seed(util::util_pseudorandom_time_point_seed::value()); eng_dig().seed(util::util_pseudorandom_time_point_seed::value()); auto result_is_ok = true; #if (defined(__cpp_lib_to_chars) && (__cpp_lib_to_chars >= 201611L)) for(auto i = static_cast(UINT8_C(0)); i < static_cast(loop_count_hi); ++i) { // Verify write to_chars() and read back from string of unsigned uintwide_t. // Use all three bases octal, decimal, and hexadecimal. using to_chars_storage_array_oct_type = std::array(local_uintwide_t_small_unsigned_type::wr_string_max_buffer_size_oct())>; using to_chars_storage_array_dec_type = std::array(local_uintwide_t_small_unsigned_type::wr_string_max_buffer_size_dec())>; using to_chars_storage_array_hex_type = std::array(local_uintwide_t_small_unsigned_type::wr_string_max_buffer_size_hex())>; constexpr auto char_fill = '\0'; to_chars_storage_array_oct_type arr_oct { }; arr_oct.fill(char_fill); to_chars_storage_array_dec_type arr_dec { }; arr_dec.fill(char_fill); to_chars_storage_array_hex_type arr_hex { }; arr_hex.fill(char_fill); auto u_gen = generate_wide_integer_value(); using std::to_chars; const auto result_oct_as_chars = to_chars(arr_oct.data(), arr_oct.data() + arr_oct.size(), u_gen, 8); const auto result_dec_as_chars = to_chars(arr_dec.data(), arr_dec.data() + arr_dec.size(), u_gen, 10); const auto result_hex_as_chars = to_chars(arr_hex.data(), arr_hex.data() + arr_hex.size(), u_gen, 16); auto result_oct_as_str = std::string(arr_oct.data()); result_oct_as_str.insert(result_oct_as_str.begin(), static_cast(UINT8_C(1)), '0'); const auto result_dec_as_str = std::string(arr_dec.data()); auto result_hex_as_str = std::string(arr_hex.data()); result_hex_as_str.insert(result_hex_as_str.begin(), static_cast(UINT8_C(1)), 'x'); result_hex_as_str.insert(result_hex_as_str.begin(), static_cast(UINT8_C(1)), '0'); const local_uintwide_t_small_unsigned_type u_from_string_oct(result_oct_as_str.c_str()); const local_uintwide_t_small_unsigned_type u_from_string_dec(result_dec_as_str.c_str()); const local_uintwide_t_small_unsigned_type u_from_string_hex(result_hex_as_str.c_str()); const auto result_u_to_from_string_oct_is_ok = ((u_gen == u_from_string_oct) && (result_oct_as_chars.ec == std::errc())); const auto result_u_to_from_string_dec_is_ok = ((u_gen == u_from_string_dec) && (result_dec_as_chars.ec == std::errc())); const auto result_u_to_from_string_hex_is_ok = ((u_gen == u_from_string_hex) && (result_hex_as_chars.ec == std::errc())); result_is_ok = (result_u_to_from_string_oct_is_ok && result_is_ok); result_is_ok = (result_u_to_from_string_dec_is_ok && result_is_ok); result_is_ok = (result_u_to_from_string_hex_is_ok && result_is_ok); } for(auto i = static_cast(UINT8_C(0)); i < static_cast(loop_count_hi); ++i) { // Verify write to_chars() and read back from string of signed uintwide_t. // Use only base decimal. using to_chars_storage_array_dec_type = std::array(local_uintwide_t_small_signed_type::wr_string_max_buffer_size_dec())>; constexpr auto char_fill = '\0'; to_chars_storage_array_dec_type arr_dec { }; arr_dec.fill(char_fill); auto n_gen = generate_wide_integer_value(false); using std::to_chars; const auto result_dec_as_chars = to_chars(arr_dec.data(), arr_dec.data() + arr_dec.size(), n_gen, 10); static_cast(result_dec_as_chars); const auto result_dec_as_str = std::string(arr_dec.data()); const local_uintwide_t_small_signed_type n_from_string_dec(result_dec_as_str.c_str()); const auto result_n_to_from_string_dec_is_ok = (n_gen == n_from_string_dec); result_is_ok = (result_n_to_from_string_dec_is_ok && result_is_ok); } { using from_chars_vals_array_type = std::array(UINT8_C(3))>; using from_chars_str_array_type = std::array(UINT8_C(3))>; const from_chars_str_array_type from_chars_strings_dec = {{ std::string("15144643305917092583843275533505256431413500728112133531049985787371431391573"), std::string("32468694466796117852331137634732746549554240939117027005983522724188427316919"), std::string("22464118857179526662260684853039985803178920824202321315045157411980838523643") }}; const from_chars_vals_array_type from_chars_vals = {{ local_uintwide_t_small_signed_type(from_chars_strings_dec[0U].c_str()), local_uintwide_t_small_signed_type(from_chars_strings_dec[1U].c_str()), local_uintwide_t_small_signed_type(from_chars_strings_dec[2U].c_str()) }}; // Test constexpr-context of from_chars(). { constexpr local_uintwide_t_small_signed_type compile_time_val("22464118857179526662260684853039985803178920824202321315045157411980838523643"); static_assert(::constexpr_test_from_chars() == compile_time_val, "Error: Can not perform constexpr-from_chars() at compile-time"); const auto result_constexpr_test_from_chars_is_ok = (::constexpr_test_from_chars() == compile_time_val); result_is_ok = (result_constexpr_test_from_chars_is_ok && result_is_ok); } // Successively test one success and one known failing case. { auto str_false = from_chars_strings_dec.back(); local_uintwide_t_small_signed_type val_false { }; const auto fc_result_ok = from_chars(str_false.data(), str_false.data() + str_false.length(), val_false, 10); // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) const auto result_false_correct_is_ok = ((val_false == from_chars_vals.back()) && (fc_result_ok.ec == std::errc())); // Now ensure that the failing test-string is actually wrong and should/will fail. str_false.back() = 'Z'; const auto fc_result_not_ok = from_chars(str_false.data(), str_false.data() + str_false.length(), val_false, 10); // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) const auto result_false_false_is_ok = ((val_false != from_chars_vals.back()) && (fc_result_not_ok.ec != std::errc()) && (val_false == 0)); const auto result_both_vals_false_are_ok = (result_false_correct_is_ok && result_false_false_is_ok); result_is_ok = (result_both_vals_false_are_ok && result_is_ok); } const from_chars_str_array_type from_chars_strings_hex = {{ std::string("0x217B907900B4119043037FA80D33976A08FCA38343D756BD61F2744C273FF155"), std::string("0x47C8A13C35D6BFC31A75B127413559683B4FD3E725429CBC7221E5351BD2EEB7"), std::string("0x31AA3D9E5925FC857426C365669F7EB75DBBF8AD4AEB98B03375D9FE1DB952FB") }}; const from_chars_str_array_type from_chars_strings_oct = {{ std::string("02057344074400550106202060157752006463456650107712160320753526572607623504604717770525"), std::string("04371050236065655377030647266111640465262640732375174711241234570710417123243364567267"), std::string("03065217317131113762053502330331263237375335355677425522565630540315656637703556251373") }}; // Test from_chars for decimal, hexadecimal and octal bases. { // Decimal. std::size_t index { }; for(const auto& str : from_chars_strings_dec) { local_uintwide_t_small_signed_type val { }; const auto fc_result = from_chars(str.data(), str.data() + str.length(), val, 10); // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) const auto result_from_chars_val_is_ok = ((val == from_chars_vals[index]) && (fc_result.ec == std::errc())); // NOLINT(cppcoreguidelines-pro-bounds-constant-array-index) result_is_ok = (result_from_chars_val_is_ok && result_is_ok); ++index; } } { // Hexadecimal. std::size_t index { }; for(const auto& str : from_chars_strings_hex) { local_uintwide_t_small_signed_type val { }; const auto fc_result = from_chars(str.data() + static_cast(UINT8_C(2)), str.data() + str.length(), val, 16); // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) const auto result_from_chars_val_is_ok = ((val == from_chars_vals[index]) && (fc_result.ec == std::errc())); // NOLINT(cppcoreguidelines-pro-bounds-constant-array-index) result_is_ok = (result_from_chars_val_is_ok && result_is_ok); ++index; } } { // Octal. std::size_t index { }; for(const auto& str : from_chars_strings_oct) { local_uintwide_t_small_signed_type val { }; const auto fc_result = from_chars(str.data() + static_cast(UINT8_C(1)), str.data() + str.length(), val, 8); // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) const auto result_from_chars_val_is_ok = ((val == from_chars_vals[index]) && (fc_result.ec == std::errc())); // NOLINT(cppcoreguidelines-pro-bounds-constant-array-index) result_is_ok = (result_from_chars_val_is_ok && result_is_ok); ++index; } } } #endif // (defined(__cpp_lib_to_chars) && (__cpp_lib_to_chars >= 201611L)) #if !defined(WIDE_INTEGER_DISABLE_TO_STRING) for(auto i = static_cast(UINT8_C(0)); i < static_cast(loop_count_hi); ++i) { // Verify write to_string() and read back from string of unsigned uintwide_t. auto u_gen = generate_wide_integer_value(); using std::to_string; const auto str_u = to_string(u_gen); const local_uintwide_t_small_unsigned_type u_from_string(str_u.c_str()); const auto result_u_to_from_string_is_ok = (u_gen == u_from_string); result_is_ok = (result_u_to_from_string_is_ok && result_is_ok); } for(auto i = static_cast(UINT8_C(0)); i < static_cast(loop_count_hi); ++i) { // Verify write to_string() and read back from string of signed uintwide_t. auto n_gen = generate_wide_integer_value(false); using std::to_string; const auto str_n = to_string(n_gen); const local_uintwide_t_small_signed_type n_from_string(str_n.c_str()); const auto result_n_to_from_string_is_ok = (n_gen == n_from_string); result_is_ok = (result_n_to_from_string_is_ok && result_is_ok); } { // Ensure that uintwide_t's function to_string (in namespace // math::wide_integer) does *not* conflict with the standard library's // std::to_string function name. Also ensure that ADL works properly // for uintwide_t's namespace-specific to_string function. using std::to_string; const auto u_gen = generate_wide_integer_value(); const auto n_gen = generate_wide_integer_value(false); const auto str_u = to_string(u_gen); const auto str_n = to_string(n_gen); const auto u64 = static_cast(UINT64_C(0xFFFFFFFF55555555)); const auto ni = static_cast(INT8_C(42)); const auto str_u64 = to_string(u64); const auto str_ni = to_string(ni); const auto str2_u64 = std::to_string(u64); const auto str2_ni = std::to_string(ni); const auto result_to_strings_are_ok = ( (!str_u.empty()) && (!str_n.empty()) && (!str_u64.empty()) && (!str_ni.empty()) && (!str2_u64.empty()) && (!str2_ni.empty())); result_is_ok = (result_to_strings_are_ok && result_is_ok); } #if !defined(UINTWIDE_T_REDUCE_TEST_DEPTH) for(auto i = static_cast(UINT8_C(0)); i < static_cast(UINT32_C(32)); ++i) { // Verify write to_string() and read back from string of // this test file's wide unsigned uintwide_t type. // Thereby we ensure that the to_string() function // will use dynamic allocation instead of stack allocation // in this particular test. using local_derived_uint_type = typename local_uint_backend_type::representation_type; using std::to_string; const auto u_gen = generate_wide_integer_value(); const auto str_u = to_string(u_gen); const local_derived_uint_type u_from_string(str_u.c_str()); const auto result_u_to_from_string_is_ok = (u_gen == u_from_string); result_is_ok = (result_u_to_from_string_is_ok && result_is_ok); } #endif #endif // !WIDE_INTEGER_DISABLE_TO_STRING return result_is_ok; } auto test_import_bits() -> bool; auto test_import_bits() -> bool // NOLINT(readability-function-cognitive-complexity) { eng_sgn().seed(util::util_pseudorandom_time_point_seed::value()); eng_dig().seed(util::util_pseudorandom_time_point_seed::value()); using local_boost_small_uint_backend_type = boost::multiprecision::cpp_int_backend; using local_boost_small_uint_type = boost::multiprecision::number; auto result_is_ok = true; static const std::array(UINT8_C(2))> msv_options = { true, false }; for(const auto& msv_first : msv_options) // NOLINT { for(auto i = static_cast(UINT8_C(0)); i < static_cast(loop_count_lo); ++i) { // Verify import_bits() and compare with Boost control value(s). // The input and output ranges have elements having the same widths. // Use the full bit width and representation length of uintwide_t. using local_representation_type = typename local_uintwide_t_small_unsigned_type::representation_type; using local_input_value_type = typename local_representation_type::value_type; auto u_gen = generate_wide_integer_value(); local_representation_type bits(u_gen.crepresentation()); if(msv_first) { std::reverse(bits.begin(), bits.end()); } local_uintwide_t_small_unsigned_type val_uintwide_t { }; local_boost_small_uint_type val_boost { }; const auto oscillated_chunk_size = static_cast ( static_cast(i % 2U) == 0U ? static_cast(std::numeric_limits::digits) : 0U ); static_cast(import_bits(val_uintwide_t, bits.cbegin(), bits.cend(), oscillated_chunk_size, msv_first)); static_cast(import_bits(val_boost, bits.cbegin(), bits.cend(), oscillated_chunk_size, msv_first)); // NOLINT using std::to_string; const auto str_uintwide_t = to_string(val_uintwide_t); const auto str_boost = val_boost.str(); const auto result_import_bits_is_ok = ((str_uintwide_t == str_boost) && (u_gen == val_uintwide_t)); result_is_ok = (result_import_bits_is_ok && result_is_ok); } } for(const auto& msv_first : msv_options) // NOLINT { static const std::array(UINT8_C(3))> bits_for_chunks = { 7U, 9U, 15U }; for(const auto& chunk_size : bits_for_chunks) { for(auto i = static_cast(UINT8_C(0)); i < static_cast(loop_count_lo); ++i) { // Verify import_bits() and compare with Boost control value(s). // The input and output ranges have elements having the same widths. // Use various input bit counts less than the result limb's width. // Use the full size of elements in the wide integer for the // distance of the input range. using local_representation_type = typename local_uintwide_t_small_unsigned_type::representation_type; auto u_gen = generate_wide_integer_value(); local_representation_type bits(u_gen.crepresentation()); if(msv_first) { std::reverse(bits.begin(), bits.end()); } local_uintwide_t_small_unsigned_type val_uintwide_t { }; local_boost_small_uint_type val_boost { }; using std::to_string; static_cast(import_bits(val_uintwide_t, bits.cbegin(), bits.cend(), chunk_size, msv_first)); static_cast(import_bits(val_boost, bits.cbegin(), bits.cend(), chunk_size, msv_first)); // NOLINT const auto str_uintwide_t = to_string(val_uintwide_t); const auto str_boost = val_boost.str(); const auto result_import_bits_is_ok = (str_uintwide_t == str_boost); result_is_ok = (result_import_bits_is_ok && result_is_ok); } } } for(const auto& msv_first : msv_options) // NOLINT { for(auto i = static_cast(UINT8_C(0)); i < static_cast(loop_count_lo); ++i) { // Verify import_bits() and compare with Boost control value(s). // The input and output ranges have elements having different widths. // Use various input bit counts exceeding the result limb's width. // Use the full size of elements in the wide integer for the // distance of the input range. using local_representation_type = typename local_uintwide_t_small_unsigned_type::representation_type; using local_input_value_type = typename local_representation_type::value_type; auto u_gen = generate_wide_integer_value(); local_representation_type bits(u_gen.crepresentation()); #if defined(WIDE_INTEGER_NAMESPACE) using local_input_double_width_value_type = typename WIDE_INTEGER_NAMESPACE::math::wide_integer::detail::uint_type_helper(std::numeric_limits::digits * 2)>::exact_unsigned_type; #else using local_input_double_width_value_type = typename ::math::wide_integer::detail::uint_type_helper(std::numeric_limits::digits * 2)>::exact_unsigned_type; #endif using local_double_width_input_array_type = std::array; local_double_width_input_array_type bits_double_width; { using local_size_type = typename local_representation_type::size_type; auto index = static_cast(UINT8_C(0)); for(auto& elem : bits_double_width) { #if defined(WIDE_INTEGER_NAMESPACE) using WIDE_INTEGER_NAMESPACE::math::wide_integer::detail::make_large; #else using ::math::wide_integer::detail::make_large; #endif const auto index_plus_one = static_cast ( index + static_cast(UINT8_C(1)) ); #if defined(WIDE_INTEGER_NAMESPACE) elem = make_large(*WIDE_INTEGER_NAMESPACE::math::wide_integer::detail::advance_and_point(bits.cbegin(), index), *WIDE_INTEGER_NAMESPACE::math::wide_integer::detail::advance_and_point(bits.cbegin(), index_plus_one)); #else elem = make_large(*::math::wide_integer::detail::advance_and_point(bits.cbegin(), index), *::math::wide_integer::detail::advance_and_point(bits.cbegin(), index_plus_one)); #endif index = static_cast(index + static_cast(UINT8_C(2))); } } local_uintwide_t_small_unsigned_type val_uintwide_t { }; local_boost_small_uint_type val_boost { }; using std::to_string; static_cast(import_bits(val_uintwide_t, bits_double_width.cbegin(), bits_double_width.cend(), static_cast(std::numeric_limits::digits), msv_first)); static_cast(import_bits(val_boost, bits_double_width.cbegin(), bits_double_width.cend(), static_cast(std::numeric_limits::digits), msv_first)); // NOLINT const auto str_uintwide_t = to_string(val_uintwide_t); const auto str_boost = val_boost.str(); const auto result_import_bits_is_ok = (str_uintwide_t == str_boost); result_is_ok = (result_import_bits_is_ok && result_is_ok); } } for(const auto& msv_first : msv_options) // NOLINT { for(auto i = static_cast(UINT8_C(0)); i < static_cast(loop_count_lo); ++i) { // Verify import_bits() and compare with Boost control value(s). // Use various input bit counts exceeding the result limb's width. // Use only part of the size of elements in the wide integer for the // distance of the input range. using local_representation_type = typename local_uintwide_t_small_unsigned_type::representation_type; using local_input_value_type = typename local_representation_type::value_type; auto u_gen = generate_wide_integer_value(); using local_representation_less_wide_type = std::array(static_cast(local_uintwide_t_small_unsigned_type::number_of_limbs) - 2U)>; local_representation_less_wide_type bits { }; std::copy(u_gen.crepresentation().cbegin(), #if defined(WIDE_INTEGER_NAMESPACE) WIDE_INTEGER_NAMESPACE::math::wide_integer::detail::advance_and_point(u_gen.crepresentation().cbegin(), std::tuple_size::value), #else ::math::wide_integer::detail::advance_and_point(u_gen.crepresentation().cbegin(), std::tuple_size::value), #endif bits.begin()); #if defined(WIDE_INTEGER_NAMESPACE) using local_input_double_width_value_type = typename WIDE_INTEGER_NAMESPACE::math::wide_integer::detail::uint_type_helper(std::numeric_limits::digits * 2)>::exact_unsigned_type; #else using local_input_double_width_value_type = typename ::math::wide_integer::detail::uint_type_helper(std::numeric_limits::digits * 2)>::exact_unsigned_type; #endif using local_double_width_less_wide_input_array_type = std::array::value / 2U>; static_assert(std::tuple_size::value == static_cast(static_cast(static_cast(local_uintwide_t_small_unsigned_type::number_of_limbs) / 2U) - 1U), "Error: Type definition widths are not OK"); local_double_width_less_wide_input_array_type bits_double_width; { using local_size_type = typename local_representation_type::size_type; auto index = static_cast(UINT8_C(0)); for(auto& elem : bits_double_width) { #if defined(WIDE_INTEGER_NAMESPACE) using WIDE_INTEGER_NAMESPACE::math::wide_integer::detail::make_large; #else using ::math::wide_integer::detail::make_large; #endif const auto index_plus_one = static_cast ( index + static_cast(UINT8_C(1)) ); elem = make_large(bits[index], bits[index_plus_one]); // NOLINT(cppcoreguidelines-pro-bounds-constant-array-index) index = static_cast(index + static_cast(UINT8_C(2))); } } local_uintwide_t_small_unsigned_type val_uintwide_t { }; local_boost_small_uint_type val_boost { }; using std::to_string; static_cast(import_bits(val_uintwide_t, bits_double_width.cbegin(), bits_double_width.cend(), static_cast(std::numeric_limits::digits), msv_first)); static_cast(import_bits(val_boost, bits_double_width.cbegin(), bits_double_width.cend(), static_cast(std::numeric_limits::digits), msv_first)); // NOLINT const auto str_uintwide_t = to_string(val_uintwide_t); const auto str_boost = val_boost.str(); const auto result_import_bits_is_ok = (str_uintwide_t == str_boost); result_is_ok = (result_import_bits_is_ok && result_is_ok); } } { // Additional verification of import_bits(). const std::array bits_in = { static_cast(UINT32_C(0x5555AAAA)) }; using chunk_sizes_array_type = std::array(UINT8_C(4))>; static const chunk_sizes_array_type various_chunk_sizes = { 0U, 32U, 24U, 2U }; static const std::array::value> various_import_results = { static_cast(UINT32_C(0x5555AAAA)), static_cast(UINT32_C(0x5555AAAA)), static_cast(UINT32_C(0x0055AAAA)), static_cast(UINT32_C(2)) }; for(auto i = static_cast(UINT8_C(0)); i < various_chunk_sizes.size(); ++i) { auto u = local_uintwide_t_small_unsigned_type { }; static_cast ( import_bits(u, bits_in.cbegin(), bits_in.cend(), various_chunk_sizes[i]) // NOLINT(cppcoreguidelines-pro-bounds-constant-array-index) ); const auto result_import_is_ok = (u == various_import_results[i]); // NOLINT(cppcoreguidelines-pro-bounds-constant-array-index) result_is_ok = (result_import_is_ok && result_is_ok); } } return result_is_ok; } auto test_export_bits() -> bool; auto test_export_bits() -> bool // NOLINT(readability-function-cognitive-complexity) { eng_sgn().seed(util::util_pseudorandom_time_point_seed::value()); eng_dig().seed(util::util_pseudorandom_time_point_seed::value()); using local_boost_small_uint_backend_type = boost::multiprecision::cpp_int_backend; using local_boost_small_uint_type = boost::multiprecision::number; auto result_is_ok = true; static const std::array(UINT8_C(2))> msv_options = { true, false }; for(const auto& msv_first : msv_options) // NOLINT { for(auto i = static_cast(UINT8_C(0)); i < static_cast(loop_count_lo); ++i) { // Verify export_bits() and compare with Boost control value(s). // The input and output ranges have elements having the same widths. // Use the full bit width and representation length of uintwide_t. using local_representation_type = typename local_uintwide_t_small_unsigned_type::representation_type; using local_input_value_type = typename local_representation_type::value_type; using std::to_string; auto val_uintwide_t = generate_wide_integer_value(); const auto val_boost = local_boost_small_uint_type(to_string(val_uintwide_t)); using local_output_array_type = std::array; using local_result_value_type = typename local_output_array_type::value_type; local_output_array_type bits_result_from_uintwide_t { }; local_output_array_type bits_result_from_boost { }; static_cast(export_bits(val_uintwide_t, bits_result_from_uintwide_t.begin(), static_cast(std::numeric_limits::digits), msv_first)); static_cast(export_bits(val_boost, bits_result_from_boost.begin(), static_cast(std::numeric_limits::digits), msv_first)); // NOLINT const auto result_export_bits_is_ok = std::equal(bits_result_from_uintwide_t.cbegin(), bits_result_from_uintwide_t.cend(), bits_result_from_boost.cbegin()); result_is_ok = (result_export_bits_is_ok && result_is_ok); } } for(const auto& msv_first : msv_options) // NOLINT { static const std::array(UINT8_C(3))> bits_for_chunks = { 7U, 9U, 15U }; for(const auto& chunk_size : bits_for_chunks) { for(auto i = static_cast(UINT8_C(0)); i < static_cast(loop_count_lo); ++i) { // Verify export_bits() and compare with Boost control value(s). // The input and output ranges have elements having the same widths. // Use various input bit counts less than the result limb's width. // Use the full size of elements in the wide integer for the // distance of the input range. using local_representation_type = typename local_uintwide_t_small_unsigned_type::representation_type; using local_input_value_type = typename local_representation_type::value_type; using std::to_string; auto val_uintwide_t = generate_wide_integer_value(); const auto val_boost = local_boost_small_uint_type(to_string(val_uintwide_t)); using local_output_vector_type = std::vector; using local_result_value_type = typename local_output_vector_type::value_type; const auto output_distance_chunk_size_has_mod = ( static_cast ( std::numeric_limits::digits % static_cast(chunk_size) ) != 0 ); const auto output_distance = static_cast ( static_cast(std::numeric_limits::digits / static_cast(chunk_size)) + static_cast ( output_distance_chunk_size_has_mod ? static_cast(UINT8_C(1)) : static_cast(UINT8_C(0)) ) ); local_output_vector_type bits_result_from_uintwide_t(output_distance, static_cast(UINT8_C(0))); local_output_vector_type bits_result_from_boost (output_distance, static_cast(UINT8_C(0))); static_cast(export_bits(val_uintwide_t, bits_result_from_uintwide_t.begin(), chunk_size, msv_first)); static_cast(export_bits(val_boost, bits_result_from_boost.begin(), chunk_size, msv_first)); // NOLINT const auto result_export_bits_is_ok = std::equal(bits_result_from_uintwide_t.cbegin(), bits_result_from_uintwide_t.cend(), bits_result_from_boost.cbegin()); result_is_ok = (result_export_bits_is_ok && result_is_ok); } } } for(const auto& msv_first : msv_options) // NOLINT { for(auto i = static_cast(UINT8_C(0)); i < static_cast(loop_count_lo); ++i) { // Verify export_bits() and compare with Boost control value(s). // The input and output ranges have elements having different widths. // Use various input bit counts exceeding the result limb's width. // Use the full size of elements in the wide integer for the // distance of the input range. using local_representation_type = typename local_uintwide_t_small_unsigned_type::representation_type; using local_input_value_type = typename local_representation_type::value_type; using std::to_string; auto val_uintwide_t = generate_wide_integer_value(); const auto val_boost = local_boost_small_uint_type(to_string(val_uintwide_t)); #if defined(WIDE_INTEGER_NAMESPACE) using local_result_double_width_value_type = typename WIDE_INTEGER_NAMESPACE::math::wide_integer::detail::uint_type_helper(std::numeric_limits::digits * 2)>::exact_unsigned_type; #else using local_result_double_width_value_type = typename ::math::wide_integer::detail::uint_type_helper(std::numeric_limits::digits * 2)>::exact_unsigned_type; #endif using local_double_width_output_array_type = std::array; local_double_width_output_array_type bits_result_double_width_from_uintwide_t { }; local_double_width_output_array_type bits_result_double_width_from_boost { }; static_cast(export_bits(val_uintwide_t, bits_result_double_width_from_uintwide_t.begin(), static_cast(std::numeric_limits::digits), msv_first)); static_cast(export_bits(val_boost, bits_result_double_width_from_boost.begin(), static_cast(std::numeric_limits::digits), msv_first)); // NOLINT const auto result_export_bits_is_ok = std::equal(bits_result_double_width_from_uintwide_t.cbegin(), bits_result_double_width_from_uintwide_t.cend(), bits_result_double_width_from_boost.cbegin()); result_is_ok = (result_export_bits_is_ok && result_is_ok); } } { // Note that export_bits uses the absolute value. // So test this feature by using negative one here. const auto val_uintwide_t = local_uintwide_t_small_signed_type(-1); const auto val_boost = local_boost_small_uint_type(1); using local_result_type = std::uint32_t; auto result_one_uintwide_t = local_result_type { }; auto result_one_boost = local_result_type { }; static_cast(export_bits(val_uintwide_t, &result_one_uintwide_t, static_cast(std::numeric_limits::digits))); static_cast(export_bits(val_boost, &result_one_boost, static_cast(std::numeric_limits::digits))); const auto result_is_one_and_compare_one_is_ok = ( (result_one_uintwide_t == result_one_boost) && (result_one_uintwide_t == 1)); result_is_ok = (result_is_one_and_compare_one_is_ok && result_is_ok); } return result_is_ok; } auto test_edge_uintwide_t_backend() -> bool; auto test_edge_uintwide_t_backend() -> bool { using local_small_uintwide_t_backend_type = boost::multiprecision::uintwide_t_backend; using local_small_uintwide_t_type = boost::multiprecision::number; auto result_is_ok = true; { // This odd-looking code is intended to pick up some non-covered lines // in the Boost-intended uintwide_t_backend class. local_small_uintwide_t_type gcd_max { 0 }; for(auto i = static_cast(UINT8_C(0)); i < static_cast(UINT32_C(64)); ++i) { const auto u = generate_wide_integer_value(); const auto v = generate_wide_integer_value(); const auto gcd_uv = gcd(-u, -v); if(gcd_uv > gcd_max) { gcd_max = gcd_uv; } } const bool result_gcd_is_ok = (gcd_max > 0); result_is_ok = (result_gcd_is_ok && result_is_ok); } return result_is_ok; } namespace from_pr_454 { auto test_proj_specific_containers() -> bool; auto test_proj_specific_containers() -> bool { bool result_is_ok { true }; { // Test container comparisons. #if defined(WIDE_INTEGER_NAMESPACE) using local_dynamic_array_type = WIDE_INTEGER_NAMESPACE::math::wide_integer::detail::dynamic_array; #else using local_dynamic_array_type = ::math::wide_integer::detail::dynamic_array; #endif using ctrl_container_type = std::vector; const local_uintwide_t_small_unsigned_type local_one (one_as_small_unsigned_type()); const local_uintwide_t_small_unsigned_type local_two (local_one + local_one); const local_uintwide_t_small_unsigned_type local_three(local_two + local_one); const local_uintwide_t_small_unsigned_type local_four (local_three + local_one); local_dynamic_array_type lhs_orig { local_one, local_two, local_three }; local_dynamic_array_type rhs_same { local_one, local_two, local_three }; local_dynamic_array_type rhs_less { local_one, local_two, local_two }; local_dynamic_array_type rhs_grtr { local_one, local_two, local_four }; ctrl_container_type ctrl_lhs_orig(lhs_orig.cbegin(), lhs_orig.cend()); ctrl_container_type ctrl_rhs_same(rhs_same.cbegin(), rhs_same.cend()); ctrl_container_type ctrl_rhs_less(rhs_less.cbegin(), rhs_less.cend()); ctrl_container_type ctrl_rhs_grtr(rhs_grtr.cbegin(), rhs_grtr.cend()); local_dynamic_array_type lhs_zero_size(std::size_t { UINT8_C(0) }); ctrl_container_type ctrl_rhs_zero_size(std::size_t { UINT8_C(0) }); bool result_compare_is_ok { }; result_compare_is_ok = ((lhs_orig == rhs_same) == (ctrl_lhs_orig == ctrl_rhs_same)); result_is_ok = (result_compare_is_ok && result_is_ok); result_compare_is_ok = ( (lhs_orig > rhs_less) == (ctrl_lhs_orig > ctrl_rhs_less)); result_is_ok = (result_compare_is_ok && result_is_ok); result_compare_is_ok = ( (lhs_orig >= rhs_less) == (ctrl_lhs_orig >= ctrl_rhs_less)); result_is_ok = (result_compare_is_ok && result_is_ok); result_compare_is_ok = ( (lhs_orig != rhs_less) == (ctrl_lhs_orig != ctrl_rhs_less)); result_is_ok = (result_compare_is_ok && result_is_ok); result_compare_is_ok = ((!(lhs_orig == rhs_less)) == (!(ctrl_lhs_orig == ctrl_rhs_less))); result_is_ok = (result_compare_is_ok && result_is_ok); result_compare_is_ok = ( (lhs_orig < rhs_grtr) == (ctrl_lhs_orig < ctrl_rhs_grtr)); result_is_ok = (result_compare_is_ok && result_is_ok); result_compare_is_ok = ( (lhs_orig <= rhs_grtr) == (ctrl_lhs_orig <= ctrl_rhs_grtr)); result_is_ok = (result_compare_is_ok && result_is_ok); result_compare_is_ok = ( (lhs_orig != rhs_grtr) == (ctrl_lhs_orig != ctrl_rhs_grtr)); result_is_ok = (result_compare_is_ok && result_is_ok); result_compare_is_ok = ((!(lhs_orig == rhs_grtr)) == (!(ctrl_lhs_orig == ctrl_rhs_grtr))); result_is_ok = (result_compare_is_ok && result_is_ok); result_compare_is_ok = ((lhs_orig == rhs_same) == (ctrl_lhs_orig == ctrl_rhs_same)); result_is_ok = (result_compare_is_ok && result_is_ok); const bool result_zero_is_ok = ( (lhs_zero_size.size() == std::size_t { UINT8_C(0) }) && (lhs_zero_size < rhs_same) && ((lhs_zero_size < rhs_same) == (ctrl_container_type(std::size_t { UINT8_C(0) }) < ctrl_rhs_same)) && ((lhs_zero_size == local_dynamic_array_type(std::size_t { UINT8_C(0) })) == (ctrl_container_type(std::size_t { UINT8_C(0) }) == ctrl_rhs_zero_size)) ); result_is_ok = (result_zero_is_ok && result_is_ok); { local_dynamic_array_type rhs_shrt { local_one, local_two }; ctrl_container_type ctrl_rhs_shrt(rhs_shrt.cbegin(), rhs_shrt.cend()); #if defined(WIDE_INTEGER_NAMESPACE) using WIDE_INTEGER_NAMESPACE::math::wide_integer::detail::lexicographical_compare_unsafe; #else using ::math::wide_integer::detail::lexicographical_compare_unsafe; #endif bool result_b0 { lexicographical_compare_unsafe ( lhs_orig.cbegin(), lhs_orig.cend(), rhs_shrt.cbegin(), rhs_shrt.cend() ) }; bool result_b1 { lexicographical_compare_unsafe ( ctrl_lhs_orig.cbegin(), ctrl_lhs_orig.cend(), ctrl_rhs_shrt.cbegin(), ctrl_rhs_shrt.cend() ) }; const bool result_lex_compare_is_ok = (result_b0 == result_b1); result_is_ok = (result_lex_compare_is_ok && result_is_ok); } } return result_is_ok; } } // namespace from_pr_454 } // namespace test_uintwide_t_edge // LCOV_EXCL_START #if defined(WIDE_INTEGER_NAMESPACE) auto WIDE_INTEGER_NAMESPACE::math::wide_integer::test_uintwide_t_edge_cases() -> bool #else auto ::math::wide_integer::test_uintwide_t_edge_cases() -> bool #endif { test_uintwide_t_edge::eng_sgn().seed(::util::util_pseudorandom_time_point_seed::value()); test_uintwide_t_edge::eng_dig().seed(::util::util_pseudorandom_time_point_seed::value()); auto result_is_ok = true; #if !defined(UINTWIDE_T_REDUCE_TEST_DEPTH) result_is_ok = (test_uintwide_t_edge::test_various_edge_operations () && result_is_ok); #endif // LCOV_EXCL_STOP result_is_ok = (test_uintwide_t_edge::test_various_ostream_ops () && result_is_ok); result_is_ok = (test_uintwide_t_edge::test_various_roots_and_pow_etc () && result_is_ok); result_is_ok = (test_uintwide_t_edge::test_ops_n_half_by_n_half () && result_is_ok); result_is_ok = (test_uintwide_t_edge::test_small_prime_and_non_prime () && result_is_ok); result_is_ok = (test_uintwide_t_edge::test_some_gcd_and_equal_left_right () && result_is_ok); result_is_ok = (test_uintwide_t_edge::test_various_isolated_edge_cases () && result_is_ok); result_is_ok = (test_uintwide_t_edge::test_to_and_from_chars_and_to_string () && result_is_ok); result_is_ok = (test_uintwide_t_edge::test_import_bits () && result_is_ok); result_is_ok = (test_uintwide_t_edge::test_export_bits () && result_is_ok); result_is_ok = (test_uintwide_t_edge::test_edge_uintwide_t_backend () && result_is_ok); result_is_ok = (test_uintwide_t_edge::from_pr_454::test_proj_specific_containers () && result_is_ok); return result_is_ok; } // LCOV_EXCL_START auto test_uintwide_t_edge::zero_as_limb() -> const typename test_uintwide_t_edge::local_uintwide_t_small_unsigned_type::limb_type& { using local_limb_type = typename local_uintwide_t_small_unsigned_type::limb_type; static const auto local_zero_limb = static_cast(UINT8_C(0)); return local_zero_limb; } auto test_uintwide_t_edge::zero_as_small_unsigned_type() -> const test_uintwide_t_edge::local_uintwide_t_small_unsigned_type& // LCOV_EXCL_LINE { using local_limb_type = typename local_uintwide_t_small_unsigned_type::limb_type; static const auto local_zero_as_small_unsigned_type = local_uintwide_t_small_unsigned_type ( static_cast(UINT8_C(0)) ); return local_zero_as_small_unsigned_type; } extern const test_uintwide_t_edge::local_uintwide_t_small_unsigned_type local_one_plus_as_small_signed_type; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables,cert-err58-cpp,) extern const test_uintwide_t_edge::local_uintwide_t_small_signed_type local_one_minus_as_small_signed_type; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables,cert-err58-cpp,) auto test_uintwide_t_edge::one_as_small_unsigned_type() -> const test_uintwide_t_edge::local_uintwide_t_small_unsigned_type& { return local_one_plus_as_small_signed_type; } auto test_uintwide_t_edge::m_one_as_small_signed_type() -> const test_uintwide_t_edge::local_uintwide_t_small_signed_type& { return local_one_minus_as_small_signed_type; } const test_uintwide_t_edge::local_uintwide_t_small_unsigned_type local_one_plus_as_small_signed_type // NOLINT(cppcoreguidelines-avoid-non-const-global-variables,cert-err58-cpp) { static_cast>(UINT8_C(1)) }; const test_uintwide_t_edge::local_uintwide_t_small_signed_type local_one_minus_as_small_signed_type // NOLINT(cppcoreguidelines-avoid-non-const-global-variables,cert-err58-cpp) { static_cast>(INT8_C(-1)) }; auto local_inf_f () -> float { return std::numeric_limits::infinity(); } auto local_inf_d () -> double { return std::numeric_limits::infinity(); } auto local_inf_ld() -> long double { return std::numeric_limits::infinity(); } // LCOV_EXCL_STOP #if (BOOST_VERSION < 108000) #if ((defined(__clang__) && (__clang_major__ > 9)) && !defined(__APPLE__)) #pragma GCC diagnostic pop #endif #endif #if (defined(__GNUC__) && !defined(__clang__) && (__GNUC__ >= 12)) #pragma GCC diagnostic pop #endif #if defined(__GNUC__) #if (BOOST_VERSION < 108000) #pragma GCC diagnostic pop #pragma GCC diagnostic pop #pragma GCC diagnostic pop #else #pragma GCC diagnostic pop #pragma GCC diagnostic pop #endif #endif #if (((BOOST_VERSION == 108000) || (BOOST_VERSION == 108100)) && defined(BOOST_NO_EXCEPTIONS)) #if defined(__clang__) #pragma GCC diagnostic pop #endif #if defined(_MSC_VER) #pragma warning(pop) #endif #endif ================================================ FILE: test/test_uintwide_t_examples.cpp ================================================ /////////////////////////////////////////////////////////////////////////////// // Copyright Christopher Kormanyos 2019 - 2026. // Distributed under the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt // or copy at http://www.boost.org/LICENSE_1_0.txt) // #include #include #include #include #include #if defined(WIDE_INTEGER_NAMESPACE) auto WIDE_INTEGER_NAMESPACE::math::wide_integer::test_uintwide_t_examples() -> bool #else auto ::math::wide_integer::test_uintwide_t_examples() -> bool #endif { const auto flg = std::cout.flags(); bool result_is_ok = true; result_is_ok = (math::wide_integer::example000_numeric_limits () && result_is_ok); std::cout << "result_is_ok after example000_numeric_limits : " << std::boolalpha << result_is_ok << std::endl; result_is_ok = (math::wide_integer::example000a_builtin_convert () && result_is_ok); std::cout << "result_is_ok after example000a_builtin_convert : " << std::boolalpha << result_is_ok << std::endl; result_is_ok = (math::wide_integer::example001_mul_div () && result_is_ok); std::cout << "result_is_ok after example001_mul_div : " << std::boolalpha << result_is_ok << std::endl; result_is_ok = (math::wide_integer::example001a_div_mod () && result_is_ok); std::cout << "result_is_ok after example001a_div_mod : " << std::boolalpha << result_is_ok << std::endl; result_is_ok = (math::wide_integer::example002_shl_shr () && result_is_ok); std::cout << "result_is_ok after example002_shl_shr : " << std::boolalpha << result_is_ok << std::endl; result_is_ok = (math::wide_integer::example003_sqrt () && result_is_ok); std::cout << "result_is_ok after example003_sqrt : " << std::boolalpha << result_is_ok << std::endl; result_is_ok = (math::wide_integer::example003a_cbrt () && result_is_ok); std::cout << "result_is_ok after example003a_cbrt : " << std::boolalpha << result_is_ok << std::endl; result_is_ok = (math::wide_integer::example004_rootk_pow () && result_is_ok); std::cout << "result_is_ok after example004_rootk_pow : " << std::boolalpha << result_is_ok << std::endl; result_is_ok = (math::wide_integer::example005_powm () && result_is_ok); std::cout << "result_is_ok after example005_powm : " << std::boolalpha << result_is_ok << std::endl; result_is_ok = (math::wide_integer::example005a_pow_factors_of_p99 () && result_is_ok); std::cout << "result_is_ok after example005a_pow_factors_of_p99 : " << std::boolalpha << result_is_ok << std::endl; result_is_ok = (math::wide_integer::example006_gcd () && result_is_ok); std::cout << "result_is_ok after example006_gcd : " << std::boolalpha << result_is_ok << std::endl; result_is_ok = (math::wide_integer::example007_random_generator () && result_is_ok); std::cout << "result_is_ok after example007_random_generator : " << std::boolalpha << result_is_ok << std::endl; result_is_ok = (math::wide_integer::example008_miller_rabin_prime () && result_is_ok); std::cout << "result_is_ok after example008_miller_rabin_prime : " << std::boolalpha << result_is_ok << std::endl; result_is_ok = (math::wide_integer::example008a_miller_rabin_prime () && result_is_ok); std::cout << "result_is_ok after example008a_miller_rabin_prime : " << std::boolalpha << result_is_ok << std::endl; result_is_ok = (math::wide_integer::example008b_solovay_strassen_prime () && result_is_ok); std::cout << "result_is_ok after example008b_solovay_strassen_prime : " << std::boolalpha << result_is_ok << std::endl; result_is_ok = (math::wide_integer::example009_timed_mul () && result_is_ok); std::cout << "result_is_ok after example009_timed_mul : " << std::boolalpha << result_is_ok << std::endl; result_is_ok = (math::wide_integer::example009a_timed_mul_4_by_4 () && result_is_ok); std::cout << "result_is_ok after example009a_timed_mul_4_by_4 : " << std::boolalpha << result_is_ok << std::endl; result_is_ok = (math::wide_integer::example009b_timed_mul_8_by_8 () && result_is_ok); std::cout << "result_is_ok after example009b_timed_mul_8_by_8 : " << std::boolalpha << result_is_ok << std::endl; result_is_ok = (math::wide_integer::example010_uint48_t () && result_is_ok); std::cout << "result_is_ok after example010_uint48_t : " << std::boolalpha << result_is_ok << std::endl; result_is_ok = (math::wide_integer::example011_uint24_t () && result_is_ok); std::cout << "result_is_ok after example011_uint24_t : " << std::boolalpha << result_is_ok << std::endl; #if !(defined(_MSC_VER) && defined(_DEBUG)) result_is_ok = (math::wide_integer::example012_rsa_crypto () && result_is_ok); std::cout << "result_is_ok after example012_rsa_crypto : " << std::boolalpha << result_is_ok << std::endl; #endif result_is_ok = (math::wide_integer::example013_ecdsa_sign_verify () && result_is_ok); std::cout << "result_is_ok after example013_ecdsa_sign_verify : " << std::boolalpha << result_is_ok << std::endl; result_is_ok = (math::wide_integer::example014_pi_spigot_wide () && result_is_ok); std::cout << "result_is_ok after example014_pi_spigot_wide : " << std::boolalpha << result_is_ok << std::endl; std::cout.flags(flg); return result_is_ok; } ================================================ FILE: test/test_uintwide_t_float_convert.cpp ================================================ /////////////////////////////////////////////////////////////////////////////// // Copyright Christopher Kormanyos 2021 - 2025. // Distributed under the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt // or copy at http://www.boost.org/LICENSE_1_0.txt) // #include #include #include #if !defined(BOOST_VERSION) #error BOOST_VERSION is not defined. Ensure that is properly included. #endif #if ((BOOST_VERSION >= 107900) && !defined(BOOST_MP_STANDALONE)) #define BOOST_MP_STANDALONE #endif #if ((BOOST_VERSION >= 108000) && !defined(BOOST_NO_EXCEPTIONS)) #define BOOST_NO_EXCEPTIONS #endif #if (((BOOST_VERSION == 108000) || (BOOST_VERSION == 108100)) && defined(BOOST_NO_EXCEPTIONS)) #if defined(__clang__) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wsometimes-uninitialized" #endif #if defined(_MSC_VER) #pragma warning(push) #pragma warning(disable : 4701) #endif #endif #if (BOOST_VERSION < 108000) #if defined(__GNUC__) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wconversion" #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wsign-conversion" #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wunused-parameter" #endif #endif #if (defined(__GNUC__) && !defined(__clang__) && (__GNUC__ >= 12)) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wrestrict" #endif #if (BOOST_VERSION < 108000) #if ((defined(__clang__) && (__clang_major__ > 9)) && !defined(__APPLE__)) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wdeprecated-copy" #endif #endif #include #include #include #if defined(__clang__) #if defined __has_feature && __has_feature(thread_sanitizer) #define UINTWIDE_T_REDUCE_TEST_DEPTH #endif #elif defined(__GNUC__) #if defined(__SANITIZE_THREAD__) || defined(WIDE_INTEGER_HAS_COVERAGE) #define UINTWIDE_T_REDUCE_TEST_DEPTH #endif #elif defined(_MSC_VER) #if defined(_DEBUG) #define UINTWIDE_T_REDUCE_TEST_DEPTH #endif #endif namespace local_float_convert { auto engine_man() -> std::mt19937&; auto engine_sgn() -> std::ranlux24_base&; auto engine_e10() -> std::linear_congruential_engine&; // NOLINT(cppcoreguidelines-avoid-magic-numbers,readability-magic-numbers) auto engine_man() -> std::mt19937& { static std::mt19937 my_engine_man; return my_engine_man; } // NOLINT(cert-msc32-c,cert-msc51-cpp) auto engine_sgn() -> std::ranlux24_base& { static std::ranlux24_base my_engine_sgn; return my_engine_sgn; } // NOLINT(cert-msc32-c,cert-msc51-cpp) auto engine_e10() -> std::linear_congruential_engine& { static std::linear_congruential_engine my_engine_e10; return my_engine_e10; } // NOLINT(cert-msc32-c,cert-msc51-cpp,cppcoreguidelines-avoid-magic-numbers,readability-magic-numbers) template auto unsigned_dist_maker(const UnsignedIntegralType lo, const UnsignedIntegralType hi) -> std::uniform_int_distribution { return std::uniform_int_distribution(lo, hi); } template auto get_random_float() -> FloatingPointType { using local_builtin_float_type = FloatingPointType; static std::uniform_real_distribution dist_man ( static_cast(0.0F), static_cast(1.0F) ); static auto dist_sgn = unsigned_dist_maker(static_cast(UINT8_C(0)), static_cast(UINT8_C(1))); static auto dist_e10 = unsigned_dist_maker(LoExp10, HiExp10); using std::pow; const auto p10 = dist_e10(engine_e10()); const local_builtin_float_type e10 = pow(static_cast(10.0F), static_cast(p10)); const local_builtin_float_type a = dist_man(engine_man()) * e10; const bool is_neg = (dist_sgn(engine_sgn()) != 0); const local_builtin_float_type f = ((!is_neg) ? a : -a); return f; } template auto get_random_digit_string(std::string& str) -> void // NOLINT(google-runtime-references) { static_assert(MinDigitsToGet >= 2U, "Error: The minimum number of digits to get must be 2 or more"); static auto dist_sgn = unsigned_dist_maker(static_cast(UINT8_C(0)), static_cast(UINT8_C(1))); static auto dist_len = unsigned_dist_maker(MinDigitsToGet, MaxDigitsToGet); static auto dist_first = unsigned_dist_maker(static_cast(UINT8_C(1)), static_cast(UINT8_C(9))); static auto dist_following = unsigned_dist_maker(static_cast(UINT8_C(0)), static_cast(UINT8_C(9))); const bool is_neg = (dist_sgn(engine_sgn()) != 0); const auto len = dist_len(engine_e10()); auto pos = static_cast(0U); if(is_neg) { str.resize(len + 1U); str.at(pos) = '-'; ++pos; } else { str.resize(len); } str.at(pos) = static_cast ( dist_first(engine_man()) + static_cast::result_type>(UINT32_C(0x30)) ); ++pos; while(pos < str.length()) { str.at(pos) = static_cast ( dist_following(engine_man()) + static_cast::result_type>(UINT32_C(0x30)) ); ++pos; } } template auto hexlexical_cast(const UnsignedIntegralType& u) -> std::string { std::stringstream ss; ss << std::hex << u; return ss.str(); } } // namespace local_float_convert #if defined(WIDE_INTEGER_NAMESPACE) auto WIDE_INTEGER_NAMESPACE::math::wide_integer::test_uintwide_t_float_convert() -> bool #else auto ::math::wide_integer::test_uintwide_t_float_convert() -> bool #endif { constexpr auto digits2 = static_cast(256U); using boost_uint_backend_type = boost::multiprecision::cpp_int_backend; using boost_sint_backend_type = boost::multiprecision::cpp_int_backend; using boost_uint_type = boost::multiprecision::number; using boost_sint_type = boost::multiprecision::number; #if defined(WIDE_INTEGER_HAS_LIMB_TYPE_UINT64) using local_limb_type = std::uint64_t; #else using local_limb_type = std::uint32_t; #endif #if defined(WIDE_INTEGER_NAMESPACE) using local_uint_type = WIDE_INTEGER_NAMESPACE::math::wide_integer::uintwide_t; using local_sint_type = WIDE_INTEGER_NAMESPACE::math::wide_integer::uintwide_t; #else using local_uint_type = ::math::wide_integer::uintwide_t; using local_sint_type = ::math::wide_integer::uintwide_t; #endif local_float_convert::engine_man().seed(::util::util_pseudorandom_time_point_seed::value()); local_float_convert::engine_sgn().seed(::util::util_pseudorandom_time_point_seed::value()); local_float_convert::engine_e10().seed(::util::util_pseudorandom_time_point_seed::value::result_type>()); // NOLINT(cppcoreguidelines-avoid-magic-numbers,readability-magic-numbers) bool result_is_ok = true; #if !defined(UINTWIDE_T_REDUCE_TEST_DEPTH) for(auto i = static_cast(0U); i < static_cast(UINT32_C(0x80000)); ++i) #else for(auto i = static_cast(0U); i < static_cast(UINT32_C(0x10000)); ++i) #endif { const auto f = local_float_convert::get_random_float(); auto n_boost = static_cast(f); auto n_local = static_cast(f); const std::string str_boost_signed = local_float_convert::hexlexical_cast(static_cast(n_boost)); const std::string str_local_signed = local_float_convert::hexlexical_cast(static_cast(n_local)); result_is_ok = ((str_boost_signed == str_local_signed) && result_is_ok); } #if !defined(UINTWIDE_T_REDUCE_TEST_DEPTH) for(auto i = static_cast(0U); i < static_cast(UINT32_C(0x80000)); ++i) #else for(auto i = static_cast(0U); i < static_cast(UINT32_C(0x10000)); ++i) #endif { const auto d = local_float_convert::get_random_float(); auto n_boost = static_cast(d); auto n_local = static_cast(d); const std::string str_boost_signed = local_float_convert::hexlexical_cast(static_cast(n_boost)); const std::string str_local_signed = local_float_convert::hexlexical_cast(static_cast(n_local)); result_is_ok = ((str_boost_signed == str_local_signed) && result_is_ok); } local_float_convert::engine_man().seed(::util::util_pseudorandom_time_point_seed::value()); local_float_convert::engine_sgn().seed(::util::util_pseudorandom_time_point_seed::value()); local_float_convert::engine_e10().seed(::util::util_pseudorandom_time_point_seed::value::result_type>()); // NOLINT(cppcoreguidelines-avoid-magic-numbers,readability-magic-numbers) #if !defined(UINTWIDE_T_REDUCE_TEST_DEPTH) for(auto i = static_cast(0U); i < static_cast(UINT32_C(0x100000)); ++i) #else for(auto i = static_cast(0U); i < static_cast(UINT32_C(0x20000)); ++i) #endif { std::string str_digits; local_float_convert::get_random_digit_string<31U>(str_digits); // NOLINT(cppcoreguidelines-avoid-magic-numbers,readability-magic-numbers) const auto n_boost = boost_sint_type(str_digits.c_str()); const auto n_local = local_sint_type(str_digits.c_str()); const auto f_boost = static_cast(n_boost); const auto f_local = static_cast(n_local); using std::fabs; constexpr auto cast_tol_float = static_cast(std::numeric_limits::epsilon() * 2.0F); const float closeness = fabs(1.0F - fabs(f_boost / f_local)); const bool result_f_is_ok = (closeness < cast_tol_float); result_is_ok = (result_f_is_ok && result_is_ok); } #if !defined(UINTWIDE_T_REDUCE_TEST_DEPTH) for(auto i = static_cast(0U); i < static_cast(UINT32_C(0x40000)); ++i) #else for(auto i = static_cast(0U); i < static_cast(UINT32_C(0x08000)); ++i) #endif { std::string str_digits; local_float_convert::get_random_digit_string<71U>(str_digits); // NOLINT(cppcoreguidelines-avoid-magic-numbers,readability-magic-numbers) const auto n_boost = boost_sint_type(str_digits.c_str()); const auto n_local = local_sint_type(str_digits.c_str()); const auto d_boost = static_cast(n_boost); const auto d_local = static_cast(n_local); using std::fabs; constexpr auto cast_tol_double = static_cast(std::numeric_limits::epsilon() * 2.0); const double closeness = fabs(1.0 - fabs(d_boost / d_local)); const bool result_f_is_ok = (closeness < cast_tol_double); result_is_ok = (result_f_is_ok && result_is_ok); } return result_is_ok; } #if (BOOST_VERSION < 108000) #if ((defined(__clang__) && (__clang_major__ > 9)) && !defined(__APPLE__)) #pragma GCC diagnostic pop #endif #endif #if (defined(__GNUC__) && !defined(__clang__) && (__GNUC__ >= 12)) #pragma GCC diagnostic pop #endif #if (BOOST_VERSION < 108000) #if defined(__GNUC__) #pragma GCC diagnostic pop #pragma GCC diagnostic pop #pragma GCC diagnostic pop #endif #endif #if (((BOOST_VERSION == 108000) || (BOOST_VERSION == 108100)) && defined(BOOST_NO_EXCEPTIONS)) #if defined(__clang__) #pragma GCC diagnostic pop #endif #if defined(_MSC_VER) #pragma warning(pop) #endif #endif ================================================ FILE: test/test_uintwide_t_int_convert.cpp ================================================ /////////////////////////////////////////////////////////////////////////////// // Copyright Christopher Kormanyos 2021 - 2025. // Distributed under the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt // or copy at http://www.boost.org/LICENSE_1_0.txt) // #include #include #include #if !defined(BOOST_VERSION) #error BOOST_VERSION is not defined. Ensure that is properly included. #endif #if ((BOOST_VERSION >= 107900) && !defined(BOOST_MP_STANDALONE)) #define BOOST_MP_STANDALONE #endif #if ((BOOST_VERSION >= 108000) && !defined(BOOST_NO_EXCEPTIONS)) #define BOOST_NO_EXCEPTIONS #endif #if (((BOOST_VERSION == 108000) || (BOOST_VERSION == 108100)) && defined(BOOST_NO_EXCEPTIONS)) #if defined(__clang__) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wsometimes-uninitialized" #endif #if defined(_MSC_VER) #pragma warning(push) #pragma warning(disable : 4701) #endif #endif #if (BOOST_VERSION < 108000) #if defined(__GNUC__) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wconversion" #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wsign-conversion" #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wunused-parameter" #endif #endif #if (defined(__GNUC__) && !defined(__clang__) && (__GNUC__ >= 12)) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wrestrict" #endif #if (BOOST_VERSION < 108000) #if ((defined(__clang__) && (__clang_major__ > 9)) && !defined(__APPLE__)) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wdeprecated-copy" #endif #endif #include #include #include namespace local_int_convert { auto engine_val() -> std::mt19937&; auto engine_sgn() -> std::ranlux24_base&; auto engine_len() -> std::linear_congruential_engine&; // NOLINT(cppcoreguidelines-avoid-magic-numbers,readability-magic-numbers) auto engine_val() -> std::mt19937& { static std::mt19937 my_engine_val; return my_engine_val; } // NOLINT(cert-msc32-c,cert-msc51-cpp) auto engine_sgn() -> std::ranlux24_base& { static std::ranlux24_base my_engine_sgn; return my_engine_sgn; } // NOLINT(cert-msc32-c,cert-msc51-cpp) auto engine_len() -> std::linear_congruential_engine& { static std::linear_congruential_engine my_engine_len; return my_engine_len; } // NOLINT(cert-msc32-c,cert-msc51-cpp,cppcoreguidelines-avoid-magic-numbers,readability-magic-numbers) template auto get_random_digit_string(std::string& str) -> void // NOLINT(google-runtime-references) { static_assert(MinDigitsToGet >= 2U, "Error: The minimum number of digits to get must be 2 or more"); static std::uniform_int_distribution dist_sgn ( static_cast(UINT8_C(0)), static_cast(UINT8_C(1)) ); static std::uniform_int_distribution dist_len ( MinDigitsToGet, MaxDigitsToGet ); static std::uniform_int_distribution dist_first ( static_cast(UINT8_C(1)), static_cast(UINT8_C(9)) ); static std::uniform_int_distribution dist_following ( static_cast(UINT8_C(0)), static_cast(UINT8_C(9)) ); const bool is_neg = (dist_sgn(engine_sgn()) != 0); const auto len = static_cast(dist_len(engine_len())); std::string::size_type pos = 0U; if(is_neg) { str.resize(len + 1U); str.at(pos) = '-'; ++pos; } else { str.resize(len); } str.at(pos) = static_cast ( dist_first(engine_val()) + static_cast::result_type>(UINT32_C(0x30)) ); ++pos; while(pos < str.length()) { str.at(pos) = static_cast ( dist_following(engine_val()) + static_cast::result_type>(UINT32_C(0x30)) ); ++pos; } } template auto hexlexical_cast(const UnsignedIntegralType& u) -> std::string { std::stringstream ss; ss << std::hex << u; return ss.str(); } } // namespace local_int_convert #if defined(WIDE_INTEGER_NAMESPACE) auto WIDE_INTEGER_NAMESPACE::math::wide_integer::test_uintwide_t_int_convert() -> bool #else auto ::math::wide_integer::test_uintwide_t_int_convert() -> bool #endif { constexpr auto digits2 = static_cast(UINT32_C(256)); using boost_sint_backend_type = boost::multiprecision::cpp_int_backend; using boost_sint_type = boost::multiprecision::number; #if defined(WIDE_INTEGER_HAS_LIMB_TYPE_UINT64) using local_limb_type = std::uint64_t; #else using local_limb_type = std::uint32_t; #endif #if defined(WIDE_INTEGER_NAMESPACE) using local_sint_type = WIDE_INTEGER_NAMESPACE::math::wide_integer::uintwide_t; #else using local_sint_type = ::math::wide_integer::uintwide_t; #endif local_int_convert::engine_val().seed(::util::util_pseudorandom_time_point_seed::value()); local_int_convert::engine_sgn().seed(::util::util_pseudorandom_time_point_seed::value()); local_int_convert::engine_len().seed(::util::util_pseudorandom_time_point_seed::value::result_type>()); // NOLINT(cppcoreguidelines-avoid-magic-numbers,readability-magic-numbers) bool result_is_ok = true; for(auto i = static_cast(UINT32_C(0)); i < static_cast(UINT32_C(0x100000)); ++i) { std::string str_digits; local_int_convert::get_random_digit_string(UINT32_C(18)), static_cast(UINT32_C(2))>(str_digits); const auto n_boost = boost_sint_type(str_digits.c_str()); const auto n_local = local_sint_type(str_digits.c_str()); const auto n_ctrl_boost = static_cast(n_boost); const auto n_ctrl_local = static_cast(n_local); const bool result_n_is_ok = (n_ctrl_boost == n_ctrl_local); result_is_ok = (result_n_is_ok && result_is_ok); } return result_is_ok; } #if (BOOST_VERSION < 108000) #if ((defined(__clang__) && (__clang_major__ > 9)) && !defined(__APPLE__)) #pragma GCC diagnostic pop #endif #endif #if (defined(__GNUC__) && !defined(__clang__) && (__GNUC__ >= 12)) #pragma GCC diagnostic pop #endif #if (BOOST_VERSION < 108000) #if defined(__GNUC__) #pragma GCC diagnostic pop #pragma GCC diagnostic pop #pragma GCC diagnostic pop #endif #endif #if (((BOOST_VERSION == 108000) || (BOOST_VERSION == 108100)) && defined(BOOST_NO_EXCEPTIONS)) #if defined(__clang__) #pragma GCC diagnostic pop #endif #if defined(_MSC_VER) #pragma warning(pop) #endif #endif ================================================ FILE: test/test_uintwide_t_n_base.cpp ================================================ /////////////////////////////////////////////////////////////////////////////// // Copyright Christopher Kormanyos 2021 - 2025. // Distributed under the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt // or copy at http://www.boost.org/LICENSE_1_0.txt) // #include auto test_uintwide_t_n_base::my_random_generator() -> test_uintwide_t_n_base::random_engine_type& { static random_engine_type my_generator; // NOLINT(cert-msc32-c,cert-msc51-cpp) return my_generator; } ================================================ FILE: test/test_uintwide_t_n_base.h ================================================ /////////////////////////////////////////////////////////////////////////////// // Copyright Christopher Kormanyos 2019 - 2025. // Distributed under the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt // or copy at http://www.boost.org/LICENSE_1_0.txt) // #ifndef TEST_UINTWIDE_T_N_BASE_2019_12_29_H // NOLINT(llvm-header-guard) #define TEST_UINTWIDE_T_N_BASE_2019_12_29_H #include #include #include #include #include #if !defined(BOOST_VERSION) #error BOOST_VERSION is not defined. Ensure that is properly included. #endif #if ((BOOST_VERSION >= 107900) && !defined(BOOST_MP_STANDALONE)) #define BOOST_MP_STANDALONE #endif #if ((BOOST_VERSION >= 108000) && !defined(BOOST_NO_EXCEPTIONS)) #define BOOST_NO_EXCEPTIONS #endif #if (BOOST_VERSION < 108000) #if defined(__GNUC__) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wconversion" #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wsign-conversion" #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wunused-parameter" #endif #endif #if (defined(__GNUC__) && !defined(__clang__) && (__GNUC__ >= 12)) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wrestrict" #endif #if (BOOST_VERSION < 108000) #if ((defined(__clang__) && (__clang_major__ > 9)) && !defined(__APPLE__)) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wdeprecated-copy" #endif #endif #include #include #include class test_uintwide_t_n_base { public: virtual ~test_uintwide_t_n_base() = default; #if defined(WIDE_INTEGER_NAMESPACE) WIDE_INTEGER_NODISCARD virtual auto get_digits2() const -> WIDE_INTEGER_NAMESPACE::math::wide_integer::size_t = 0; #else WIDE_INTEGER_NODISCARD virtual auto get_digits2() const -> ::math::wide_integer::size_t = 0; #endif WIDE_INTEGER_NODISCARD auto size() const -> std::size_t { return number_of_cases; } virtual auto initialize() -> void = 0; test_uintwide_t_n_base() = delete; test_uintwide_t_n_base(const test_uintwide_t_n_base&) = delete; test_uintwide_t_n_base( test_uintwide_t_n_base&&) = delete; auto operator=(const test_uintwide_t_n_base&) -> test_uintwide_t_n_base& = delete; auto operator=( test_uintwide_t_n_base&&) -> test_uintwide_t_n_base& = delete; protected: using random_engine_type = std::linear_congruential_engine; // NOLINT(cppcoreguidelines-avoid-magic-numbers,readability-magic-numbers) static auto my_random_generator() -> random_engine_type&; explicit test_uintwide_t_n_base(const std::size_t count) : number_of_cases(count) { } template static auto hexlexical_cast(const UnsignedIntegralType& u) -> std::string { std::stringstream ss; ss << std::hex << u; return ss.str(); } template static auto declexical_cast(const IntegralType& n) -> std::string { std::stringstream ss; ss << std::dec << n; return ss.str(); } template static auto get_equal_random_test_values_boost_and_local_n( OtherLocalUintType* u_local, OtherBoostUintType* u_boost, const std::size_t count) -> void { using other_local_uint_type = OtherLocalUintType; using other_boost_uint_type = OtherBoostUintType; my_random_generator().seed(util::util_pseudorandom_time_point_seed::value()); #if defined(WIDE_INTEGER_NAMESPACE) using distribution_type = WIDE_INTEGER_NAMESPACE::math::wide_integer::uniform_int_distribution; #else using distribution_type = ::math::wide_integer::uniform_int_distribution; #endif distribution_type distribution; std::atomic_flag rnd_lock = ATOMIC_FLAG_INIT; my_concurrency::parallel_for ( static_cast(0U), count, [&u_local, &u_boost, &distribution, &rnd_lock](std::size_t i) { while(rnd_lock.test_and_set()) { ; } const other_local_uint_type a = distribution(my_random_generator()); rnd_lock.clear(); u_local[i] = a; // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) u_boost[i] = other_boost_uint_type("0x" + hexlexical_cast(a)); // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) } ); } private: const std::size_t number_of_cases; }; #if (BOOST_VERSION < 108000) #if ((defined(__clang__) && (__clang_major__ > 9)) && !defined(__APPLE__)) #pragma GCC diagnostic pop #endif #endif #if (defined(__GNUC__) && !defined(__clang__) && (__GNUC__ >= 12)) #pragma GCC diagnostic pop #endif #if (BOOST_VERSION < 108000) #if defined(__GNUC__) #pragma GCC diagnostic pop #pragma GCC diagnostic pop #pragma GCC diagnostic pop #endif #endif #endif // TEST_UINTWIDE_T_N_BASE_2019_12_29_H ================================================ FILE: test/test_uintwide_t_n_binary_ops_base.cpp ================================================ /////////////////////////////////////////////////////////////////////////////// // Copyright Christopher Kormanyos 2019 - 2025. // Distributed under the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt // or copy at http://www.boost.org/LICENSE_1_0.txt) // #include #if !defined(BOOST_VERSION) #error BOOST_VERSION is not defined. Ensure that is properly included. #endif #if ((BOOST_VERSION >= 107900) && !defined(BOOST_MP_STANDALONE)) #define BOOST_MP_STANDALONE #endif #if ((BOOST_VERSION >= 108000) && !defined(BOOST_NO_EXCEPTIONS)) #define BOOST_NO_EXCEPTIONS #endif #if (((BOOST_VERSION == 108000) || (BOOST_VERSION == 108100)) && defined(BOOST_NO_EXCEPTIONS)) #if defined(__clang__) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wsometimes-uninitialized" #endif #if defined(_MSC_VER) #pragma warning(push) #pragma warning(disable : 4701) #endif #endif #if (BOOST_VERSION < 108000) #if defined(__GNUC__) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wconversion" #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wsign-conversion" #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wunused-parameter" #endif #endif #if (defined(__GNUC__) && !defined(__clang__) && (__GNUC__ >= 12)) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wrestrict" #endif #if (BOOST_VERSION < 108000) #if ((defined(__clang__) && (__clang_major__ > 9)) && !defined(__APPLE__)) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wdeprecated-copy" #endif #endif #include auto test_uintwide_t_n_binary_ops_base::my_rnd() -> std::random_device& { static std::random_device my_random_device; return my_random_device; } auto test_uintwide_t_n_binary_ops_base::my_gen() -> test_uintwide_t_n_binary_ops_base::random_generator_type& { static random_generator_type my_generator(my_rnd()()); return my_generator; } #if (BOOST_VERSION < 108000) #if ((defined(__clang__) && (__clang_major__ > 9)) && !defined(__APPLE__)) #pragma GCC diagnostic pop #endif #endif #if (defined(__GNUC__) && !defined(__clang__) && (__GNUC__ >= 12)) #pragma GCC diagnostic pop #endif #if (BOOST_VERSION < 108000) #if defined(__GNUC__) #pragma GCC diagnostic pop #pragma GCC diagnostic pop #pragma GCC diagnostic pop #endif #endif #if (((BOOST_VERSION == 108000) || (BOOST_VERSION == 108100)) && defined(BOOST_NO_EXCEPTIONS)) #if defined(__clang__) #pragma GCC diagnostic pop #endif #if defined(_MSC_VER) #pragma warning(pop) #endif #endif ================================================ FILE: test/test_uintwide_t_n_binary_ops_base.h ================================================ /////////////////////////////////////////////////////////////////////////////// // Copyright Christopher Kormanyos 2019 - 2025. // Distributed under the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt // or copy at http://www.boost.org/LICENSE_1_0.txt) // #ifndef TEST_UINTWIDE_T_N_BINARY_OPS_BASE_2019_12_19_H // NOLINT(llvm-header-guard) #define TEST_UINTWIDE_T_N_BINARY_OPS_BASE_2019_12_19_H #include #include #include #include #include class test_uintwide_t_n_binary_ops_base : public test_uintwide_t_n_base { public: explicit test_uintwide_t_n_binary_ops_base(const std::size_t count) : test_uintwide_t_n_base(count) { } test_uintwide_t_n_binary_ops_base() = delete; test_uintwide_t_n_binary_ops_base(const test_uintwide_t_n_binary_ops_base&) = delete; test_uintwide_t_n_binary_ops_base( test_uintwide_t_n_binary_ops_base&&) = delete; auto operator=(const test_uintwide_t_n_binary_ops_base&) -> test_uintwide_t_n_binary_ops_base& = delete; auto operator=( test_uintwide_t_n_binary_ops_base&&) -> test_uintwide_t_n_binary_ops_base& = delete; ~test_uintwide_t_n_binary_ops_base() override = default; virtual auto do_test(std::size_t rounds) -> bool = 0; protected: using random_generator_type = std::mersenne_twister_engine(UINT32_C( 32)), static_cast(UINT32_C(624)), static_cast(UINT32_C(397)), static_cast(UINT32_C( 31)), UINT32_C(0x9908B0DF), static_cast(UINT32_C( 11)), UINT32_C(0xFFFFFFFF), static_cast(UINT32_C( 7)), UINT32_C(0x9D2C5680), static_cast(UINT32_C( 15)), UINT32_C(0xEFC60000), static_cast(UINT32_C( 18)), UINT32_C(1812433253)>; static auto my_rnd() -> std::random_device&; static auto my_gen() -> random_generator_type&; }; #endif // TEST_UINTWIDE_T_N_BINARY_OPS_BASE_2019_12_19_H ================================================ FILE: test/test_uintwide_t_n_binary_ops_mul_div_4_by_4_template.h ================================================ /////////////////////////////////////////////////////////////////////////////// // Copyright Christopher Kormanyos 2021 - 2025. // Distributed under the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt // or copy at http://www.boost.org/LICENSE_1_0.txt) // #ifndef TEST_UINTWIDE_T_N_BINARY_OPS_MUL_DIV_4_BY_4_TEMPLATE_2021_03_04_H // NOLINT(llvm-header-guard) #define TEST_UINTWIDE_T_N_BINARY_OPS_MUL_DIV_4_BY_4_TEMPLATE_2021_03_04_H #include #include #include #include #include #if defined(WIDE_INTEGER_NAMESPACE) template class test_uintwide_t_n_binary_ops_mul_div_4_by_4_template; #else template class test_uintwide_t_n_binary_ops_mul_div_4_by_4_template; #endif #if defined(WIDE_INTEGER_NAMESPACE) template #else template #endif class test_uintwide_t_n_binary_ops_mul_div_4_by_4_template // NOLINT(cppcoreguidelines-special-member-functions,hicpp-special-member-functions) ::digits * 4 == MyWidth2) && (std::is_fundamental::value) && (std::is_integral ::value) && (std::is_unsigned ::value))>> : public test_uintwide_t_n_binary_ops_base { private: #if defined(WIDE_INTEGER_NAMESPACE) static constexpr auto digits2 = static_cast(MyWidth2); #else static constexpr auto digits2 = static_cast(MyWidth2); #endif #if defined(WIDE_INTEGER_NAMESPACE) WIDE_INTEGER_NODISCARD auto get_digits2 () const -> WIDE_INTEGER_NAMESPACE::math::wide_integer::size_t override { return digits2; } #else WIDE_INTEGER_NODISCARD auto get_digits2 () const -> ::math::wide_integer::size_t override { return digits2; } #endif #if defined(WIDE_INTEGER_NAMESPACE) using native_uint_cntrl_type = typename WIDE_INTEGER_NAMESPACE::math::wide_integer::detail::uint_type_helper::exact_unsigned_type; #else using native_uint_cntrl_type = typename ::math::wide_integer::detail::uint_type_helper::exact_unsigned_type; #endif using local_limb_type = MyLimbType; #if defined(WIDE_INTEGER_NAMESPACE) using local_uint_ab_type = WIDE_INTEGER_NAMESPACE::math::wide_integer::uintwide_t; #else using local_uint_ab_type = ::math::wide_integer::uintwide_t; #endif public: explicit test_uintwide_t_n_binary_ops_mul_div_4_by_4_template(const std::size_t count) : test_uintwide_t_n_binary_ops_base(count) { } ~test_uintwide_t_n_binary_ops_mul_div_4_by_4_template() override = default; auto do_test(std::size_t rounds) -> bool override { bool result_is_ok = true; for(std::size_t i = 0U; i < rounds; ++i) { std::cout << "initialize() native compare with uintwide_t: round " << i << ", digits2: " << this->get_digits2() << std::endl; this->initialize(); std::cout << "test_binary_mul() native compare with uintwide_t: round " << i << ", digits2: " << this->get_digits2() << std::endl; result_is_ok = (test_binary_mul() && result_is_ok); std::cout << "test_binary_div() native compare with uintwide_t: round " << i << ", digits2: " << this->get_digits2() << std::endl; result_is_ok = (test_binary_div() && result_is_ok); } return result_is_ok; } auto initialize() -> void override { a_local.clear(); b_local.clear(); a_cntrl.clear(); b_cntrl.clear(); a_local.resize(size()); b_local.resize(size()); a_cntrl.resize(size()); b_cntrl.resize(size()); get_equal_random_test_values_cntrl_and_local_n(a_local.data(), a_cntrl.data(), size()); get_equal_random_test_values_cntrl_and_local_n(b_local.data(), b_cntrl.data(), size()); } WIDE_INTEGER_NODISCARD auto test_binary_mul() const -> bool { std::atomic_flag test_lock = ATOMIC_FLAG_INIT; bool result_is_ok = true; my_concurrency::parallel_for ( static_cast(0U), size(), [&test_lock, &result_is_ok, this](std::size_t i) { const native_uint_cntrl_type c_cntrl = native_uint_cntrl_type(a_cntrl[i]) * b_cntrl[i]; const local_uint_ab_type c_local = static_cast(a_local[i]) * static_cast(b_local[i]); const std::string str_boost = hexlexical_cast(c_cntrl); const std::string str_local = hexlexical_cast(c_local); while(test_lock.test_and_set()) { ; } result_is_ok = ((str_boost == str_local) && result_is_ok); test_lock.clear(); } ); return result_is_ok; } WIDE_INTEGER_NODISCARD auto test_binary_div() const -> bool { std::atomic_flag test_lock = ATOMIC_FLAG_INIT; test_uintwide_t_n_binary_ops_base::my_gen().seed(util::util_pseudorandom_time_point_seed::value()); std::uniform_int_distribution<> dis(1, static_cast(digits2 - 1U)); bool result_is_ok = true; my_concurrency::parallel_for ( static_cast(0U), size(), [&test_lock, &result_is_ok, this, &dis](std::size_t i) { while(test_lock.test_and_set()) { ; } const auto right_shift_amount = static_cast(dis(my_gen())); test_lock.clear(); const native_uint_cntrl_type c_cntrl = a_cntrl[i] / (std::max)(native_uint_cntrl_type(1U), native_uint_cntrl_type(b_cntrl[i] >> right_shift_amount)); const local_uint_ab_type c_local = a_local[i] / (std::max)(local_uint_ab_type(1U), (b_local[i] >> right_shift_amount)); const std::string str_boost = hexlexical_cast(c_cntrl); const std::string str_local = hexlexical_cast(c_local); while(test_lock.test_and_set()) { ; } result_is_ok = ((str_boost == str_local) && result_is_ok); test_lock.clear(); } ); return result_is_ok; } private: std::vector a_local { }; // NOLINT(readability-identifier-naming) std::vector b_local { }; // NOLINT(readability-identifier-naming) std::vector a_cntrl { }; // NOLINT(readability-identifier-naming) std::vector b_cntrl { }; // NOLINT(readability-identifier-naming) template static auto get_equal_random_test_values_cntrl_and_local_n( OtherLocalUintType* u_local, OtherCntrlUintType* u_cntrl, const std::size_t count) -> void { using other_local_uint_type = OtherLocalUintType; using other_cntrl_uint_type = OtherCntrlUintType; test_uintwide_t_n_base::my_random_generator().seed ( util::util_pseudorandom_time_point_seed::value::result_type>() // NOLINT(cppcoreguidelines-avoid-magic-numbers,readability-magic-numbers) ); #if defined(WIDE_INTEGER_NAMESPACE) using distribution_type = WIDE_INTEGER_NAMESPACE::math::wide_integer::uniform_int_distribution; #else using distribution_type = ::math::wide_integer::uniform_int_distribution; #endif distribution_type distribution; std::atomic_flag rnd_lock = ATOMIC_FLAG_INIT; my_concurrency::parallel_for ( static_cast(0U), count, [&u_local, &u_cntrl, &distribution, &rnd_lock](std::size_t i) { while(rnd_lock.test_and_set()) { ; } const other_local_uint_type a = distribution(my_random_generator()); rnd_lock.clear(); u_local[i] = a; // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) u_cntrl[i] = static_cast(a); // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) } ); } }; #endif // TEST_UINTWIDE_T_N_BINARY_OPS_MUL_DIV_4_BY_4_TEMPLATE_2021_03_04_H ================================================ FILE: test/test_uintwide_t_n_binary_ops_mul_n_by_m_template.h ================================================ /////////////////////////////////////////////////////////////////////////////// // Copyright Christopher Kormanyos 2019 - 2025. // Distributed under the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt // or copy at http://www.boost.org/LICENSE_1_0.txt) // #ifndef TEST_UINTWIDE_T_N_BINARY_OPS_MUL_N_BY_M_TEMPLATE_2019_12_26_H // NOLINT(llvm-header-guard) #define TEST_UINTWIDE_T_N_BINARY_OPS_MUL_N_BY_M_TEMPLATE_2019_12_26_H #include #include #include #if defined(WIDE_INTEGER_NAMESPACE) template #else template #endif class test_uintwide_t_n_binary_ops_mul_n_by_m_template : public test_uintwide_t_n_binary_ops_base // NOLINT(cppcoreguidelines-special-member-functions,hicpp-special-member-functions) { private: #if defined(WIDE_INTEGER_NAMESPACE) static constexpr auto digits2a = static_cast(MyDigits2A); static constexpr auto digits2b = static_cast(MyDigits2B); #else static constexpr auto digits2a = static_cast(MyDigits2A); static constexpr auto digits2b = static_cast(MyDigits2B); #endif #if defined(WIDE_INTEGER_NAMESPACE) WIDE_INTEGER_NODISCARD auto get_digits2a() const -> WIDE_INTEGER_NAMESPACE::math::wide_integer::size_t { return digits2a; } WIDE_INTEGER_NODISCARD auto get_digits2b() const -> WIDE_INTEGER_NAMESPACE::math::wide_integer::size_t { return digits2b; } WIDE_INTEGER_NODISCARD auto get_digits2 () const -> WIDE_INTEGER_NAMESPACE::math::wide_integer::size_t override { return digits2a + digits2b; } #else WIDE_INTEGER_NODISCARD auto get_digits2a() const -> ::math::wide_integer::size_t { return digits2a; } WIDE_INTEGER_NODISCARD auto get_digits2b() const -> ::math::wide_integer::size_t { return digits2b; } WIDE_INTEGER_NODISCARD auto get_digits2 () const -> ::math::wide_integer::size_t override { return digits2a + digits2b; } #endif using boost_uint_backend_a_allocator_type = void; using boost_uint_backend_a_type = boost::multiprecision::cpp_int_backend; using boost_uint_backend_b_allocator_type = void; using boost_uint_backend_b_type = boost::multiprecision::cpp_int_backend; using boost_uint_backend_c_allocator_type = void; using boost_uint_backend_c_type = boost::multiprecision::cpp_int_backend; using boost_uint_a_type = boost::multiprecision::number; using boost_uint_b_type = boost::multiprecision::number; using boost_uint_c_type = boost::multiprecision::number; using local_limb_type = MyLimbType; #if defined(WIDE_INTEGER_NAMESPACE) using local_uint_a_type = WIDE_INTEGER_NAMESPACE::math::wide_integer::uintwide_t; using local_uint_b_type = WIDE_INTEGER_NAMESPACE::math::wide_integer::uintwide_t; using local_uint_c_type = WIDE_INTEGER_NAMESPACE::math::wide_integer::uintwide_t; #else using local_uint_a_type = ::math::wide_integer::uintwide_t; using local_uint_b_type = ::math::wide_integer::uintwide_t; using local_uint_c_type = ::math::wide_integer::uintwide_t; #endif public: explicit test_uintwide_t_n_binary_ops_mul_n_by_m_template(const std::size_t count) : test_uintwide_t_n_binary_ops_base(count) { } ~test_uintwide_t_n_binary_ops_mul_n_by_m_template() override = default; auto do_test(std::size_t rounds) -> bool override { bool result_is_ok = true; for(std::size_t i = 0U; i < rounds; ++i) { std::cout << "initialize() boost compare with uintwide_t: round " << i << ", digits2: " << this->get_digits2() << std::endl; this->initialize(); std::cout << "test_binary_mul() boost compare with uintwide_t: round " << i << ", digits2: " << this->get_digits2() << std::endl; result_is_ok = (test_binary_mul() && result_is_ok); } return result_is_ok; } auto initialize() -> void override { a_local.clear(); b_local.clear(); a_boost.clear(); b_boost.clear(); a_local.resize(size()); b_local.resize(size()); a_boost.resize(size()); b_boost.resize(size()); get_equal_random_test_values_boost_and_local_n(a_local.data(), a_boost.data(), size()); get_equal_random_test_values_boost_and_local_n(b_local.data(), b_boost.data(), size()); } WIDE_INTEGER_NODISCARD auto test_binary_mul() const -> bool { bool result_is_ok = true; std::atomic_flag test_lock = ATOMIC_FLAG_INIT; my_concurrency::parallel_for ( static_cast(0U), size(), [&test_lock, &result_is_ok, this](std::size_t i) { const boost_uint_c_type c_boost = boost_uint_c_type(a_boost[i]) * b_boost[i]; const local_uint_c_type c_local = static_cast(a_local[i]) * static_cast(b_local[i]); const std::string str_boost = hexlexical_cast(c_boost); const std::string str_local = hexlexical_cast(c_local); while(test_lock.test_and_set()) { ; } result_is_ok = ((str_boost == str_local) && result_is_ok); test_lock.clear(); } ); return result_is_ok; } private: std::vector a_local { }; // NOLINT(readability-identifier-naming) std::vector b_local { }; // NOLINT(readability-identifier-naming) std::vector a_boost { }; // NOLINT(readability-identifier-naming) std::vector b_boost { }; // NOLINT(readability-identifier-naming) }; #endif // TEST_UINTWIDE_T_N_BINARY_OPS_MUL_N_BY_M_TEMPLATE_2019_12_26_H ================================================ FILE: test/test_uintwide_t_n_binary_ops_template.h ================================================ /////////////////////////////////////////////////////////////////////////////// // Copyright Christopher Kormanyos 2019 - 2025. // Distributed under the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt // or copy at http://www.boost.org/LICENSE_1_0.txt) // #ifndef TEST_UINTWIDE_T_N_BINARY_OPS_TEMPLATE_2019_12_19_H // NOLINT(llvm-header-guard) #define TEST_UINTWIDE_T_N_BINARY_OPS_TEMPLATE_2019_12_19_H #include #include #include #include #include #include #include #if defined(WIDE_INTEGER_NAMESPACE) template #else template #endif class test_uintwide_t_n_binary_ops_template : public test_uintwide_t_n_binary_ops_base // NOLINT(cppcoreguidelines-special-member-functions,hicpp-special-member-functions) { private: #if defined(WIDE_INTEGER_NAMESPACE) static constexpr auto digits2 = static_cast(MyDigits2); #else static constexpr auto digits2 = static_cast(MyDigits2); #endif using boost_uint_backend_allocator_type = void; using boost_uint_backend_type = boost::multiprecision::cpp_int_backend; using boost_uint_type = boost::multiprecision::number; using local_limb_type = MyLimbType; #if defined(WIDE_INTEGER_NAMESPACE) using local_uint_type = WIDE_INTEGER_NAMESPACE::math::wide_integer::uintwide_t; #else using local_uint_type = ::math::wide_integer::uintwide_t; #endif public: explicit test_uintwide_t_n_binary_ops_template(const std::size_t count) : test_uintwide_t_n_binary_ops_base(count) { } ~test_uintwide_t_n_binary_ops_template() override = default; #if defined(WIDE_INTEGER_NAMESPACE) WIDE_INTEGER_NODISCARD auto get_digits2() const -> WIDE_INTEGER_NAMESPACE::math::wide_integer::size_t override { return digits2; } #else WIDE_INTEGER_NODISCARD auto get_digits2() const -> ::math::wide_integer::size_t override { return digits2; } #endif auto initialize() -> void override { a_local.clear(); b_local.clear(); a_boost.clear(); b_boost.clear(); a_local.resize(size()); b_local.resize(size()); a_boost.resize(size()); b_boost.resize(size()); get_equal_random_test_values_boost_and_local_n(a_local.data(), a_boost.data(), size()); get_equal_random_test_values_boost_and_local_n(b_local.data(), b_boost.data(), size()); } auto do_test(std::size_t rounds) -> bool override { bool result_is_ok = true; for(std::size_t i = 0U; i < rounds; ++i) { std::cout << "initialize() boost compare with uintwide_t: round " << i << ", digits2: " << this->get_digits2() << std::endl; this->initialize(); std::cout << "test_binary_add() boost compare with uintwide_t: round " << i << ", digits2: " << this->get_digits2() << std::endl; result_is_ok = (test_binary_add() && result_is_ok); std::cout << "test_binary_sub() boost compare with uintwide_t: round " << i << ", digits2: " << this->get_digits2() << std::endl; result_is_ok = (test_binary_sub() && result_is_ok); std::cout << "test_binary_mul() boost compare with uintwide_t: round " << i << ", digits2: " << this->get_digits2() << std::endl; result_is_ok = (test_binary_mul() && result_is_ok); std::cout << "test_binary_div() boost compare with uintwide_t: round " << i << ", digits2: " << this->get_digits2() << std::endl; result_is_ok = (test_binary_div() && result_is_ok); std::cout << "test_binary_mod() boost compare with uintwide_t: round " << i << ", digits2: " << this->get_digits2() << std::endl; result_is_ok = (test_binary_mod() && result_is_ok); std::cout << "test_binary_sqrt() boost compare with uintwide_t: round " << i << ", digits2: " << this->get_digits2() << std::endl; result_is_ok = (test_binary_sqrt() && result_is_ok); } return result_is_ok; } WIDE_INTEGER_NODISCARD auto test_binary_add() const -> bool { bool result_is_ok = true; std::atomic_flag test_lock = ATOMIC_FLAG_INIT; my_concurrency::parallel_for ( static_cast(0U), size(), [&test_lock, &result_is_ok, this](std::size_t i) { const boost_uint_type c_boost = a_boost[i] + b_boost[i]; const local_uint_type c_local = a_local[i] + b_local[i]; const std::string str_boost = hexlexical_cast(c_boost); const std::string str_local = hexlexical_cast(c_local); while(test_lock.test_and_set()) { ; } result_is_ok = ((str_boost == str_local) && result_is_ok); test_lock.clear(); } ); return result_is_ok; } WIDE_INTEGER_NODISCARD auto test_binary_sub() const -> bool { bool result_is_ok = true; std::atomic_flag test_lock = ATOMIC_FLAG_INIT; my_concurrency::parallel_for ( static_cast(0U), size(), [&test_lock, &result_is_ok, this](std::size_t i) { const boost_uint_type c_boost = a_boost[i] - b_boost[i]; const local_uint_type c_local = a_local[i] - b_local[i]; const std::string str_boost = hexlexical_cast(c_boost); const std::string str_local = hexlexical_cast(c_local); while(test_lock.test_and_set()) { ; } result_is_ok = ((str_boost == str_local) && result_is_ok); test_lock.clear(); } ); return result_is_ok; } WIDE_INTEGER_NODISCARD auto test_binary_mul() const -> bool { bool result_is_ok = true; std::atomic_flag test_lock = ATOMIC_FLAG_INIT; my_concurrency::parallel_for ( static_cast(0U), size(), [&test_lock, &result_is_ok, this](std::size_t i) { const boost_uint_type c_boost = a_boost[i] * b_boost[i]; const local_uint_type c_local = a_local[i] * b_local[i]; const std::string str_boost = hexlexical_cast(c_boost); const std::string str_local = hexlexical_cast(c_local); while(test_lock.test_and_set()) { ; } result_is_ok = ((str_boost == str_local) && result_is_ok); test_lock.clear(); } ); return result_is_ok; } WIDE_INTEGER_NODISCARD auto test_binary_div() const -> bool { std::atomic_flag test_lock = ATOMIC_FLAG_INIT; my_gen().seed(util::util_pseudorandom_time_point_seed::value()); std::uniform_int_distribution<> dis(1, static_cast(digits2 - 1U)); bool result_is_ok = true; my_concurrency::parallel_for ( static_cast(0U), size(), [&result_is_ok, this, &dis, &test_lock](std::size_t i) { while(test_lock.test_and_set()) { ; } const auto right_shift_amount = static_cast(dis(my_gen())); test_lock.clear(); const boost_uint_type c_boost = a_boost[i] / (std::max)(boost_uint_type(1U), boost_uint_type(b_boost[i] >> right_shift_amount)); const local_uint_type c_local = a_local[i] / (std::max)(local_uint_type(1U), (b_local[i] >> right_shift_amount)); const std::string str_boost = hexlexical_cast(c_boost); const std::string str_local = hexlexical_cast(c_local); while(test_lock.test_and_set()) { ; } result_is_ok = ((str_boost == str_local) && result_is_ok); test_lock.clear(); } ); return result_is_ok; } WIDE_INTEGER_NODISCARD auto test_binary_mod() const -> bool { std::atomic_flag test_lock = ATOMIC_FLAG_INIT; my_gen().seed(util::util_pseudorandom_time_point_seed::value()); std::uniform_int_distribution<> dis(1, static_cast(digits2 - 1U)); bool result_is_ok = true; my_concurrency::parallel_for ( static_cast(0U), size(), [&result_is_ok, this, &dis, &test_lock](std::size_t i) { while(test_lock.test_and_set()) { ; } const auto right_shift_amount = static_cast(dis(my_gen())); test_lock.clear(); const boost_uint_type c_boost = a_boost[i] % (std::max)(boost_uint_type(1U), boost_uint_type(b_boost[i] >> right_shift_amount)); const local_uint_type c_local = a_local[i] % (std::max)(local_uint_type(1U), (b_local[i] >> right_shift_amount)); const std::string str_boost = hexlexical_cast(c_boost); const std::string str_local = hexlexical_cast(c_local); while(test_lock.test_and_set()) { ; } result_is_ok = ((str_boost == str_local) && result_is_ok); test_lock.clear(); } ); return result_is_ok; } WIDE_INTEGER_NODISCARD auto test_binary_sqrt() const -> bool { bool result_is_ok = true; std::atomic_flag test_lock = ATOMIC_FLAG_INIT; my_concurrency::parallel_for ( static_cast(0U), size(), [&test_lock, &result_is_ok, this](std::size_t i) { const boost_uint_type c_boost = sqrt(a_boost[i]); const local_uint_type c_local = sqrt(a_local[i]); const std::string str_boost = hexlexical_cast(c_boost); const std::string str_local = hexlexical_cast(c_local); while(test_lock.test_and_set()) { ; } result_is_ok = ((str_boost == str_local) && result_is_ok); test_lock.clear(); } ); return result_is_ok; } private: std::vector a_local { }; // NOLINT(readability-identifier-naming) std::vector b_local { }; // NOLINT(readability-identifier-naming) std::vector a_boost { }; // NOLINT(readability-identifier-naming) std::vector b_boost { }; // NOLINT(readability-identifier-naming) }; #endif // TEST_UINTWIDE_T_N_BINARY_OPS_TEMPLATE_2019_12_19_H ================================================ FILE: test/test_uintwide_t_n_binary_ops_template_signed.h ================================================ /////////////////////////////////////////////////////////////////////////////// // Copyright Christopher Kormanyos 2021 - 2025. // Distributed under the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt // or copy at http://www.boost.org/LICENSE_1_0.txt) // #ifndef TEST_UINTWIDE_T_N_BINARY_OPS_TEMPLATE_SIGNED_2021_06_05_H // NOLINT(llvm-header-guard) #define TEST_UINTWIDE_T_N_BINARY_OPS_TEMPLATE_SIGNED_2021_06_05_H #include #include #include #include #include #include #include #if defined(WIDE_INTEGER_NAMESPACE) template #else template #endif class test_uintwide_t_n_binary_ops_template_signed : public test_uintwide_t_n_binary_ops_base // NOLINT(cppcoreguidelines-special-member-functions,hicpp-special-member-functions) { private: #if defined(WIDE_INTEGER_NAMESPACE) static constexpr auto digits2 = static_cast(MyDigits2); #else static constexpr auto digits2 = static_cast(MyDigits2); #endif using boost_uint_backend_allocator_type = void; using boost_uint_backend_type = boost::multiprecision::cpp_int_backend; using boost_sint_backend_allocator_type = void; using boost_sint_backend_type = boost::multiprecision::cpp_int_backend; using boost_uint_type = boost::multiprecision::number; using boost_sint_type = boost::multiprecision::number; using local_limb_type = MyLimbType; #if defined(WIDE_INTEGER_NAMESPACE) using local_uint_type = WIDE_INTEGER_NAMESPACE::math::wide_integer::uintwide_t; using local_sint_type = WIDE_INTEGER_NAMESPACE::math::wide_integer::uintwide_t; #else using local_uint_type = ::math::wide_integer::uintwide_t; using local_sint_type = ::math::wide_integer::uintwide_t; #endif public: explicit test_uintwide_t_n_binary_ops_template_signed(const std::size_t count) : test_uintwide_t_n_binary_ops_base(count) { } ~test_uintwide_t_n_binary_ops_template_signed() override = default; #if defined(WIDE_INTEGER_NAMESPACE) WIDE_INTEGER_NODISCARD auto get_digits2() const -> WIDE_INTEGER_NAMESPACE::math::wide_integer::size_t override { return digits2; } #else WIDE_INTEGER_NODISCARD auto get_digits2() const -> ::math::wide_integer::size_t override { return digits2; } #endif auto initialize() -> void override { a_local.clear(); b_local.clear(); a_local_signed.clear(); b_local_signed.clear(); a_boost.clear(); b_boost.clear(); a_boost_signed.clear(); b_boost_signed.clear(); a_local.resize(size()); b_local.resize(size()); a_local_signed.resize(size()); b_local_signed.resize(size()); a_boost.resize(size()); b_boost.resize(size()); a_boost_signed.resize(size()); b_boost_signed.resize(size()); get_equal_random_test_values_boost_and_local_n(a_local.data(), a_boost.data(), size()); get_equal_random_test_values_boost_and_local_n(b_local.data(), b_boost.data(), size()); std::copy(a_local.cbegin(), a_local.cend(), a_local_signed.begin()); std::copy(b_local.cbegin(), b_local.cend(), b_local_signed.begin()); std::copy(a_boost.cbegin(), a_boost.cend(), a_boost_signed.begin()); std::copy(b_boost.cbegin(), b_boost.cend(), b_boost_signed.begin()); } WIDE_INTEGER_NODISCARD auto test_binary_add() const -> bool { bool result_is_ok = true; std::atomic_flag test_lock = ATOMIC_FLAG_INIT; my_concurrency::parallel_for ( static_cast(0U), size(), [&test_lock, &result_is_ok, this](std::size_t i) { const boost_sint_type c_boost_signed = a_boost_signed[i] + b_boost_signed[i]; const local_sint_type c_local_signed = a_local_signed[i] + b_local_signed[i]; const std::string str_boost_signed = hexlexical_cast(static_cast(c_boost_signed)); const std::string str_local_signed = hexlexical_cast(static_cast(c_local_signed)); while(test_lock.test_and_set()) { ; } result_is_ok = ((str_boost_signed == str_local_signed) && result_is_ok); test_lock.clear(); } ); return result_is_ok; } WIDE_INTEGER_NODISCARD auto test_binary_sub() const -> bool { bool result_is_ok = true; std::atomic_flag test_lock = ATOMIC_FLAG_INIT; my_concurrency::parallel_for ( static_cast(0U), size(), [&test_lock, &result_is_ok, this](std::size_t i) { const boost_sint_type c_boost_signed = a_boost_signed[i] - b_boost_signed[i]; const local_sint_type c_local_signed = a_local_signed[i] - b_local_signed[i]; const std::string str_boost_signed = hexlexical_cast(static_cast(c_boost_signed)); const std::string str_local_signed = hexlexical_cast(static_cast(c_local_signed)); while(test_lock.test_and_set()) { ; } result_is_ok = ((str_boost_signed == str_local_signed) && result_is_ok); test_lock.clear(); } ); return result_is_ok; } WIDE_INTEGER_NODISCARD auto test_binary_mul() const -> bool { bool result_is_ok = true; std::atomic_flag test_lock = ATOMIC_FLAG_INIT; my_concurrency::parallel_for ( static_cast(0U), size(), [&test_lock, &result_is_ok, this](std::size_t i) { const boost_sint_type c_boost_signed = a_boost_signed[i] * b_boost_signed[i]; const local_sint_type c_local_signed = a_local_signed[i] * b_local_signed[i]; const std::string str_boost_signed = hexlexical_cast(static_cast(c_boost_signed)); const std::string str_local_signed = hexlexical_cast(static_cast(c_local_signed)); while(test_lock.test_and_set()) { ; } result_is_ok = ((str_boost_signed == str_local_signed) && result_is_ok); test_lock.clear(); } ); return result_is_ok; } WIDE_INTEGER_NODISCARD auto test_binary_div() const -> bool { bool result_is_ok = true; std::atomic_flag test_lock = ATOMIC_FLAG_INIT; my_concurrency::parallel_for ( static_cast(0U), size(), [&test_lock, &result_is_ok, this](std::size_t i) { const boost_sint_type c_boost_signed = a_boost_signed[i] / b_boost_signed[i]; const local_sint_type c_local_signed = a_local_signed[i] / b_local_signed[i]; const std::string str_boost_signed = hexlexical_cast(static_cast(c_boost_signed)); const std::string str_local_signed = hexlexical_cast(static_cast(c_local_signed)); while(test_lock.test_and_set()) { ; } result_is_ok = ((str_boost_signed == str_local_signed) && result_is_ok); test_lock.clear(); } ); return result_is_ok; } WIDE_INTEGER_NODISCARD auto test_binary_mod() const -> bool { bool result_is_ok = true; std::atomic_flag test_lock = ATOMIC_FLAG_INIT; my_concurrency::parallel_for ( static_cast(0U), size(), [&test_lock, &result_is_ok, this](std::size_t i) { const boost_sint_type c_boost_signed = a_boost_signed[i] % b_boost_signed[i]; const local_sint_type c_local_signed = a_local_signed[i] % b_local_signed[i]; const std::string str_boost_signed = hexlexical_cast(static_cast(c_boost_signed)); const std::string str_local_signed = hexlexical_cast(static_cast(c_local_signed)); while(test_lock.test_and_set()) { ; } result_is_ok = ((str_boost_signed == str_local_signed) && result_is_ok); test_lock.clear(); } ); return result_is_ok; } auto do_test(std::size_t rounds) -> bool override { bool result_is_ok = true; for(std::size_t i = 0U; i < rounds; ++i) { std::cout << "initialize() boost compare with uintwide_t: round " << i << ", digits2: " << this->get_digits2() << std::endl; this->initialize(); std::cout << "test_binary_add() boost compare with uintwide_t: round " << i << ", digits2: " << this->get_digits2() << std::endl; result_is_ok = (test_binary_add() && result_is_ok); std::cout << "test_binary_sub() boost compare with uintwide_t: round " << i << ", digits2: " << this->get_digits2() << std::endl; result_is_ok = (test_binary_sub() && result_is_ok); std::cout << "test_binary_mul() boost compare with uintwide_t: round " << i << ", digits2: " << this->get_digits2() << std::endl; result_is_ok = (test_binary_mul() && result_is_ok); std::cout << "test_binary_div() boost compare with uintwide_t: round " << i << ", digits2: " << this->get_digits2() << std::endl; result_is_ok = (test_binary_div() && result_is_ok); std::cout << "test_binary_mod() boost compare with uintwide_t: round " << i << ", digits2: " << this->get_digits2() << std::endl; result_is_ok = (test_binary_mod() && result_is_ok); } return result_is_ok; } private: std::vector a_local { }; // NOLINT(readability-identifier-naming) std::vector b_local { }; // NOLINT(readability-identifier-naming) std::vector a_local_signed { }; // NOLINT(readability-identifier-naming) std::vector b_local_signed { }; // NOLINT(readability-identifier-naming) std::vector a_boost { }; // NOLINT(readability-identifier-naming) std::vector b_boost { }; // NOLINT(readability-identifier-naming) std::vector a_boost_signed { }; // NOLINT(readability-identifier-naming) std::vector b_boost_signed { }; // NOLINT(readability-identifier-naming) }; template #if defined(WIDE_INTEGER_NAMESPACE) class test_uintwide_t_n_binary_ops_template_signed(UINT32_C(64)), std::uint16_t, AllocatorType> // NOLINT(cppcoreguidelines-special-member-functions,hicpp-special-member-functions) #else class test_uintwide_t_n_binary_ops_template_signed(UINT32_C(64)), std::uint16_t, AllocatorType> // NOLINT(cppcoreguidelines-special-member-functions,hicpp-special-member-functions) #endif : public test_uintwide_t_n_binary_ops_base { private: #if defined(WIDE_INTEGER_NAMESPACE) static constexpr auto digits2 = static_cast(UINT32_C(64)); #else static constexpr auto digits2 = static_cast(UINT32_C(64)); #endif using native_uint_type = std::uint64_t; using native_sint_type = std::int64_t; using local_limb_type = std::uint16_t; #if defined(WIDE_INTEGER_NAMESPACE) using local_uint_type = WIDE_INTEGER_NAMESPACE::math::wide_integer::uintwide_t; using local_sint_type = WIDE_INTEGER_NAMESPACE::math::wide_integer::uintwide_t; #else using local_uint_type = ::math::wide_integer::uintwide_t; using local_sint_type = ::math::wide_integer::uintwide_t; #endif public: explicit test_uintwide_t_n_binary_ops_template_signed(const std::size_t count) : test_uintwide_t_n_binary_ops_base(count) { } ~test_uintwide_t_n_binary_ops_template_signed() override = default; #if defined(WIDE_INTEGER_NAMESPACE) WIDE_INTEGER_NODISCARD auto get_digits2() const -> WIDE_INTEGER_NAMESPACE::math::wide_integer::size_t override { return digits2; } #else WIDE_INTEGER_NODISCARD auto get_digits2() const -> ::math::wide_integer::size_t override { return digits2; } #endif auto initialize() -> void override { a_local_signed.clear(); b_local_signed.clear(); a_native_signed.clear(); b_native_signed.clear(); a_local_signed.resize(size()); b_local_signed.resize(size()); a_native_signed.resize(size()); b_native_signed.resize(size()); std::mt19937_64 eng64(util::util_pseudorandom_time_point_seed::value()); std::uniform_int_distribution dst_u64(UINT64_C(1), UINT64_C(0xFFFFFFFFFFFFFFFF)); for(size_t i = 0U; i < size(); ++i) { a_native_signed[i] = static_cast(dst_u64(eng64)); b_native_signed[i] = static_cast(dst_u64(eng64)); a_local_signed[i] = static_cast(a_native_signed[i]); b_local_signed[i] = static_cast(b_native_signed[i]); } } WIDE_INTEGER_NODISCARD auto test_binary_add() const -> bool { bool result_is_ok = true; std::atomic_flag test_lock = ATOMIC_FLAG_INIT; my_concurrency::parallel_for ( static_cast(0U), size(), [&test_lock, &result_is_ok, this](std::size_t i) { const native_uint_type c_native_unsigned = static_cast(a_native_signed[i]) + static_cast(b_native_signed[i]); const native_sint_type c_native_signed = c_native_unsigned < UINT64_C(0x8000000000000000) ? static_cast(c_native_unsigned) : -static_cast(~c_native_unsigned + 1U); const local_sint_type c_local_signed = a_local_signed[i] + b_local_signed[i]; const std::string str_native_signed = declexical_cast(c_native_signed); const std::string str_local_signed = declexical_cast(c_local_signed); while(test_lock.test_and_set()) { ; } result_is_ok = ((str_native_signed == str_local_signed) && result_is_ok); test_lock.clear(); } ); return result_is_ok; } WIDE_INTEGER_NODISCARD auto test_binary_sub() const -> bool { bool result_is_ok = true; std::atomic_flag test_lock = ATOMIC_FLAG_INIT; my_concurrency::parallel_for ( static_cast(0U), size(), [&test_lock, &result_is_ok, this](std::size_t i) { const native_uint_type c_native_unsigned = static_cast(a_native_signed[i]) - static_cast(b_native_signed[i]); const native_sint_type c_native_signed = c_native_unsigned < UINT64_C(0x8000000000000000) ? static_cast(c_native_unsigned) : -static_cast(~c_native_unsigned + 1U); const local_sint_type c_local_signed = a_local_signed[i] - b_local_signed[i]; const std::string str_native_signed = declexical_cast(c_native_signed); const std::string str_local_signed = declexical_cast(c_local_signed); while(test_lock.test_and_set()) { ; } result_is_ok = ((str_native_signed == str_local_signed) && result_is_ok); test_lock.clear(); } ); return result_is_ok; } WIDE_INTEGER_NODISCARD auto test_binary_mul() const -> bool { bool result_is_ok = true; std::atomic_flag test_lock = ATOMIC_FLAG_INIT; my_concurrency::parallel_for ( static_cast(0U), size(), [&test_lock, &result_is_ok, this](std::size_t i) { const native_uint_type c_native_unsigned = static_cast(a_native_signed[i]) * static_cast(b_native_signed[i]); const native_sint_type c_native_signed = c_native_unsigned < UINT64_C(0x8000000000000000) ? static_cast(c_native_unsigned) : -static_cast(~c_native_unsigned + 1U); const local_sint_type c_local_signed = a_local_signed[i] * b_local_signed[i]; const std::string str_native_signed = declexical_cast(c_native_signed); const std::string str_local_signed = declexical_cast(c_local_signed); while(test_lock.test_and_set()) { ; } result_is_ok = ((str_native_signed == str_local_signed) && result_is_ok); test_lock.clear(); } ); return result_is_ok; } WIDE_INTEGER_NODISCARD auto test_binary_div() const -> bool { bool result_is_ok = true; std::atomic_flag test_lock = ATOMIC_FLAG_INIT; my_concurrency::parallel_for ( static_cast(0U), size(), [&test_lock, &result_is_ok, this](std::size_t i) { const native_sint_type c_native_signed = a_native_signed[i] / b_native_signed[i]; const local_sint_type c_local_signed = a_local_signed [i] / b_local_signed[i]; const std::string str_native_signed = declexical_cast(c_native_signed); const std::string str_local_signed = declexical_cast(c_local_signed); while(test_lock.test_and_set()) { ; } result_is_ok = ((str_native_signed == str_local_signed) && result_is_ok); test_lock.clear(); } ); return result_is_ok; } WIDE_INTEGER_NODISCARD auto test_binary_mod() const -> bool { bool result_is_ok = true; std::atomic_flag test_lock = ATOMIC_FLAG_INIT; my_concurrency::parallel_for ( static_cast(0U), size(), [&test_lock, &result_is_ok, this](std::size_t i) { const native_sint_type c_native_signed = a_native_signed[i] % b_native_signed[i]; const local_sint_type c_local_signed = a_local_signed [i] % b_local_signed[i]; const std::string str_native_signed = declexical_cast(c_native_signed); const std::string str_local_signed = declexical_cast(c_local_signed); while(test_lock.test_and_set()) { ; } result_is_ok = ((str_native_signed == str_local_signed) && result_is_ok); test_lock.clear(); } ); return result_is_ok; } WIDE_INTEGER_NODISCARD virtual auto test_binary_mod1() const -> bool { using local_signed_limb_type = typename local_sint_type::limb_type; bool result_is_ok = true; std::atomic_flag test_lock = ATOMIC_FLAG_INIT; my_concurrency::parallel_for ( static_cast(0U), size(), [&test_lock, &result_is_ok, this](std::size_t i) { while(test_lock.test_and_set()) { ; } const auto u = static_cast(my_distrib_1_to_0xFFFF(my_eng)); test_lock.clear(); const auto c_n = static_cast(a_native_signed[i] % u); const auto c_l = static_cast(a_local_signed [i] % u); while(test_lock.test_and_set()) { ; } result_is_ok = ((c_n == c_l) && result_is_ok); test_lock.clear(); } ); return result_is_ok; } WIDE_INTEGER_NODISCARD virtual auto test_binary_shr() const -> bool { my_gen().seed(util::util_pseudorandom_time_point_seed::value()); bool result_is_ok = true; std::atomic_flag test_lock = ATOMIC_FLAG_INIT; my_concurrency::parallel_for ( static_cast(0U), size(), [&test_lock, &result_is_ok, this](std::size_t i) { while(test_lock.test_and_set()) { ; } const auto u_shr = static_cast(my_distrib_0_to_63(my_eng)); test_lock.clear(); const native_sint_type c_native_signed = a_native_signed[i] >> u_shr; // NOLINT(hicpp-signed-bitwise) const local_sint_type c_local_signed = a_local_signed [i] >> u_shr; const bool current_result_is_zero = (c_local_signed == 0U); const bool current_result_is_ok = (current_result_is_zero || (c_native_signed == static_cast(c_local_signed))); while(test_lock.test_and_set()) { ; } result_is_ok = (current_result_is_ok && result_is_ok); test_lock.clear(); } ); return result_is_ok; } auto do_test(std::size_t rounds) -> bool override { bool result_is_ok = true; for(std::size_t i = 0U; i < rounds; ++i) { std::cout << "initialize() boost compare with uintwide_t: round " << i << ", digits2: " << this->get_digits2() << std::endl; this->initialize(); std::cout << "test_binary_add() boost compare with uintwide_t: round " << i << ", digits2: " << this->get_digits2() << std::endl; result_is_ok = (test_binary_add() && result_is_ok); std::cout << "test_binary_sub() boost compare with uintwide_t: round " << i << ", digits2: " << this->get_digits2() << std::endl; result_is_ok = (test_binary_sub() && result_is_ok); std::cout << "test_binary_mul() boost compare with uintwide_t: round " << i << ", digits2: " << this->get_digits2() << std::endl; result_is_ok = (test_binary_mul() && result_is_ok); std::cout << "test_binary_div() boost compare with uintwide_t: round " << i << ", digits2: " << this->get_digits2() << std::endl; result_is_ok = (test_binary_div() && result_is_ok); std::cout << "test_binary_mod() boost compare with uintwide_t: round " << i << ", digits2: " << this->get_digits2() << std::endl; result_is_ok = (test_binary_mod() && result_is_ok); std::cout << "test_binary_mod1() boost compare with uintwide_t: round " << i << ", digits2: " << this->get_digits2() << std::endl; result_is_ok = (test_binary_mod1() && result_is_ok); std::cout << "test_binary_shr() boost compare with uintwide_t: round " << i << ", digits2: " << this->get_digits2() << std::endl; result_is_ok = (test_binary_shr() && result_is_ok); } return result_is_ok; } private: static std::minstd_rand my_eng; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables) static std::uniform_int_distribution<> my_distrib_0_to_63; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables) static std::uniform_int_distribution<> my_distrib_1_to_0xFFFF; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables) std::vector a_local_signed { }; // NOLINT(readability-identifier-naming) std::vector b_local_signed { }; // NOLINT(readability-identifier-naming) std::vector a_native_signed { }; // NOLINT(readability-identifier-naming) std::vector b_native_signed { }; // NOLINT(readability-identifier-naming) }; #if defined(WIDE_INTEGER_NAMESPACE) template std::minstd_rand test_uintwide_t_n_binary_ops_template_signed(UINT32_C(64)), std::uint16_t, AllocatorType>::my_eng; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables,cert-err58-cpp,cert-msc32-c,cert-msc51-cpp) template std::uniform_int_distribution<> test_uintwide_t_n_binary_ops_template_signed(UINT32_C(64)), std::uint16_t, AllocatorType>::my_distrib_0_to_63(UINT16_C(0), UINT16_C(63)); // NOLINT(cppcoreguidelines-avoid-non-const-global-variables,cert-err58-cpp) template std::uniform_int_distribution<> test_uintwide_t_n_binary_ops_template_signed(UINT32_C(64)), std::uint16_t, AllocatorType>::my_distrib_1_to_0xFFFF(UINT16_C(1), UINT16_C(0xFFFF)); // NOLINT(cppcoreguidelines-avoid-non-const-global-variables,cert-err58-cpp) #else template std::minstd_rand test_uintwide_t_n_binary_ops_template_signed(UINT32_C(64)), std::uint16_t, AllocatorType>::my_eng; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables,cert-err58-cpp,cert-msc32-c,cert-msc51-cpp) template std::uniform_int_distribution<> test_uintwide_t_n_binary_ops_template_signed(UINT32_C(64)), std::uint16_t, AllocatorType>::my_distrib_0_to_63(UINT16_C(0), UINT16_C(63)); // NOLINT(cppcoreguidelines-avoid-non-const-global-variables,cert-err58-cpp) template std::uniform_int_distribution<> test_uintwide_t_n_binary_ops_template_signed(UINT32_C(64)), std::uint16_t, AllocatorType>::my_distrib_1_to_0xFFFF(UINT16_C(1), UINT16_C(0xFFFF)); // NOLINT(cppcoreguidelines-avoid-non-const-global-variables,cert-err58-cpp) #endif #endif // TEST_UINTWIDE_T_N_BINARY_OPS_TEMPLATE_SIGNED_2021_06_05_H ================================================ FILE: test/test_uintwide_t_n_number_theory_funcs_template.h ================================================ /////////////////////////////////////////////////////////////////////////////// // Copyright Christopher Kormanyos 2019 - 2025. // Distributed under the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt // or copy at http://www.boost.org/LICENSE_1_0.txt) // #ifndef TEST_UINTWIDE_T_N_NUMBER_THEORY_FUNCS_TEMPLATE_2019_12_29_H // NOLINT(llvm-header-guard) #define TEST_UINTWIDE_T_N_NUMBER_THEORY_FUNCS_TEMPLATE_2019_12_29_H #include #if defined(WIDE_INTEGER_NAMESPACE) template #else template #endif class test_uintwide_t_n_number_theory_funcs_template : public test_uintwide_t_n_base { public: #if defined(WIDE_INTEGER_NAMESPACE) static constexpr auto digits2 = static_cast(MyWidth2); #else static constexpr auto digits2 = static_cast(MyWidth2); #endif test_uintwide_t_n_number_theory_funcs_template(const std::size_t count) : test_uintwide_t_n_base(count) { } virtual ~test_uintwide_t_n_number_theory_funcs_template() = default; #if defined(WIDE_INTEGER_NAMESPACE) virtual auto get_digits2() const -> WIDE_INTEGER_NAMESPACE::math::wide_integer::size_t { return digits2; } #else virtual auto get_digits2() const -> ::math::wide_integer::size_t { return digits2; } #endif virtual auto initialize() -> void { } }; #endif // TEST_UINTWIDE_T_N_NUMBER_THEORY_FUNCS_TEMPLATE_2019_12_29_H ================================================ FILE: test/test_uintwide_t_spot_values.cpp ================================================ /////////////////////////////////////////////////////////////////////////////// // Copyright Christopher Kormanyos 2019 - 2025. // Distributed under the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt // or copy at http://www.boost.org/LICENSE_1_0.txt) // #include #include #include #include #include #include #include #include namespace from_issue_429 { auto test_uintwide_t_spot_values_from_issue_429() -> bool; auto test_uintwide_t_spot_values_from_issue_429() -> bool { #if defined(WIDE_INTEGER_NAMESPACE) using local_uint_type = WIDE_INTEGER_NAMESPACE::math::wide_integer::uint256_t; #else using local_uint_type = ::math::wide_integer::uint256_t; #endif const std::vector input ( { 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x21, 0x62, 0xff, 0xff, 0xff, 0xff, 0x21 } ); local_uint_type p0_local { }; // Import the data into the wide integer. import_bits ( p0_local, input.cbegin(), input.cend(), static_cast(UINT8_C(8)) ); std::stringstream strm_local { }; strm_local << std::hex << p0_local; const std::string str_local { strm_local.str() }; const bool result_import_is_ok { str_local == "ffffffffffffff2162ffffffff21" }; std::vector export_local(input.size()); export_bits(p0_local, export_local.begin(), static_cast(UINT8_C(8))); const bool result_export_is_ok { export_local == std::vector( { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x21, 0x62, 0xff, 0xff, 0xff, 0xff, 0x21, 0x00, 0x00, 0x00 } ) }; const bool result_import_export_is_ok { result_import_is_ok && result_export_is_ok }; return result_import_export_is_ok; } } // namespace from_issue_429 namespace from_issue_362 { auto test_uintwide_t_spot_values_from_issue_362() -> bool; auto test_uintwide_t_spot_values_from_issue_362() -> bool { #if defined(WIDE_INTEGER_NAMESPACE) using local_uint512_t = WIDE_INTEGER_NAMESPACE::math::wide_integer::uint512_t; #else using local_uint512_t = ::math::wide_integer::uint512_t; #endif const auto a = local_uint512_t(static_cast(UINT32_C(11111))); const auto b = local_uint512_t(static_cast(UINT32_C(22222))); const auto c = a * b; auto result_is_ok = (c == local_uint512_t(static_cast(UINT32_C(246908642)))); return result_is_ok; } } // namespace from_issue_362 namespace from_issue_342 { auto test_uintwide_t_spot_values_from_issue_342_pos() -> bool; auto test_uintwide_t_spot_values_from_issue_342_pos() -> bool { // See also: https://github.com/ckormanyos/wide-integer/issues/342 #if defined(WIDE_INTEGER_NAMESPACE) using local_uint128_t = WIDE_INTEGER_NAMESPACE::math::wide_integer::uint128_t; #else using local_uint128_t = ::math::wide_integer::uint128_t; #endif auto result_is_ok = true; { const local_uint128_t a = 11; const local_uint128_t b = 3; const auto r_pp = divmod(+a, +b); const auto result_pp_is_ok = ((r_pp.first == +3) && (r_pp.second == +2)); result_is_ok = (result_pp_is_ok && result_is_ok); } { const local_uint128_t a = 12; const local_uint128_t b = 3; const auto r_pp = divmod(+a, +b); const auto result_divmod_is_ok = ((r_pp.first == +4) && (r_pp.second == 0)); result_is_ok = (result_divmod_is_ok && result_is_ok); } return result_is_ok; } auto test_uintwide_t_spot_values_from_issue_342_mix() -> bool; auto test_uintwide_t_spot_values_from_issue_342_mix() -> bool { // See also: https://github.com/ckormanyos/wide-integer/issues/342 #if defined(WIDE_INTEGER_NAMESPACE) using local_int128_t = WIDE_INTEGER_NAMESPACE::math::wide_integer::int128_t; #else using local_int128_t = ::math::wide_integer::int128_t; #endif auto result_is_ok = true; { const local_int128_t a = 17; const local_int128_t b = 4; const auto r_pp = divmod(+a, +b); const auto r_pm = divmod(+a, -b); const auto r_mp = divmod(-a, +b); const auto r_mm = divmod(-a, -b); const auto result_pp_is_ok = ((r_pp.first == +4) && (r_pp.second == +1)); const auto result_pm_is_ok = ((r_pm.first == -5) && (r_pm.second == -3)); const auto result_mp_is_ok = ((r_mp.first == -5) && (r_mp.second == +3)); const auto result_mm_is_ok = ((r_mm.first == +4) && (r_mm.second == -1)); const auto result_divmod_is_ok = ( result_pp_is_ok && result_pm_is_ok && result_mp_is_ok && result_mm_is_ok ); result_is_ok = (result_divmod_is_ok && result_is_ok); } { const local_int128_t a = 12; const local_int128_t b = 3; const auto r_pp = divmod(+a, +b); const auto r_pm = divmod(+a, -b); const auto r_mp = divmod(-a, +b); const auto r_mm = divmod(-a, -b); const auto result_pp_is_ok = ((r_pp.first == +4) && (r_pp.second == 0)); const auto result_pm_is_ok = ((r_pm.first == -4) && (r_pm.second == 0)); const auto result_mp_is_ok = ((r_mp.first == -4) && (r_mp.second == 0)); const auto result_mm_is_ok = ((r_mm.first == +4) && (r_mm.second == 0)); const auto result_divmod_is_ok = ( result_pp_is_ok && result_pm_is_ok && result_mp_is_ok && result_mm_is_ok ); result_is_ok = (result_divmod_is_ok && result_is_ok); } { const local_int128_t a = 32; const local_int128_t b = 115; const auto r_pp = divmod(+a, +b); const auto r_pm = divmod(+a, -b); const auto r_mp = divmod(-a, +b); const auto r_mm = divmod(-a, -b); const auto result_pp_is_ok = ((r_pp.first == +0) && (r_pp.second == +32)); const auto result_pm_is_ok = ((r_pm.first == -1) && (r_pm.second == -83)); const auto result_mp_is_ok = ((r_mp.first == -1) && (r_mp.second == +83)); const auto result_mm_is_ok = ((r_mm.first == +0) && (r_mm.second == -32)); const auto result_divmod_is_ok = ( result_pp_is_ok && result_pm_is_ok && result_mp_is_ok && result_mm_is_ok ); result_is_ok = (result_divmod_is_ok && result_is_ok); } return result_is_ok; } } // namespace from_issue_342 namespace from_issue_339 { // See also: https://github.com/ckormanyos/wide-integer/issues/339 #if defined(WIDE_INTEGER_NAMESPACE) using uint2048 = WIDE_INTEGER_NAMESPACE::math::wide_integer::uint2048_t; using uint4096 = WIDE_INTEGER_NAMESPACE::math::wide_integer::uint4096_t; using sint2048 = WIDE_INTEGER_NAMESPACE::math::wide_integer::uintwide_t; #else using uint2048 = ::math::wide_integer::uint2048_t; using uint4096 = ::math::wide_integer::uint4096_t; using sint2048 = ::math::wide_integer::uintwide_t; #endif auto modInverse(uint2048 A, uint2048 M) -> uint2048; // NOLINT(readability-identifier-naming) auto modInverse(uint2048 A, uint2048 M) -> uint2048 // NOLINT(readability-identifier-naming) { uint4096 m0 = M; uint4096 y = 0; uint4096 x = 1; if(M == 1) { return 0; // LCOV_EXCL_LINE } while (A > 1) { uint4096 q = A / M; uint4096 t = M; M = A % M; A = t; t = y; y = x - q * y; x = t; } if (x < 0) { x += m0; // LCOV_EXCL_LINE } return x; } auto test_uintwide_t_spot_values_from_issue_339_underflow_2048_4096() -> bool; auto test_uintwide_t_spot_values_from_issue_339_underflow_2048_4096() -> bool { const auto mod_inv_unsigned = modInverse(uint2048(59), uint2048(164)); const auto result_unsigned_is_ok = ( mod_inv_unsigned == uint2048 ( "1044388881413152506691752710716624382579964249047383780384233483283953907971557456848826811934997558" "3408901067144392628379875734381857936072632360878513652779459569765437099983403615901343837183144280" "7001185594622637631883939771274567233468434458661749680790870580370407128404874011860911446797778359" "8029006686938976881787785946905630190260940599579453432823469303026696443059025015972399867714215541" "6938355598852914863182379144344967340878118726394964751001890413490084170616750936683338505510329720" "8826955076998361636941193301521379682583718809183365675122131849284636812555022599830041234478486259" "5674492194617023806505913245610825731835380087608622102834270197698202313169017678006675195485079921" "6364193702853751247840149071591354599827905133996115517942711068311340905842728842797915548497829543" "2353451706522326906139490598769300212296339568778287894844061600741294567491982305057164237715481632" "1380631045902916136926708342856440730447899971901781465763473223850267253059899795996090799469201774" "6248177184498674556592501783290704731194331655508075682218465717463732968849128195203174570024409266" "1691087414838507841192980452298185733897764810312608590300130241346718972667321649151113160292078173" "8033436090243804708340403154190311" ) ); const auto mod_inv_signed = static_cast(mod_inv_unsigned); const auto result_signed_is_ok = (mod_inv_signed == -25); const auto result_is_ok = (result_unsigned_is_ok && result_signed_is_ok); return result_is_ok; } } // namespace from_issue_339 namespace from_issue_316 { // See also: https://github.com/ckormanyos/wide-integer/issues/316 using import_export_array_type = std::array(128U)>; // NOLINT(cppcoreguidelines-avoid-magic-numbers,readability-magic-numbers) constexpr import_export_array_type bin_128_source_of_bits_imported = { 142, 215, 17, 233, 75, 7, 202, 91, 88, 53, 153, 106, 94, 112, 136, 40, 229, 3, 176, 116, 42, 179, 23, 109, 103, 70, 57, 154, 157, 110, 148, 87, 86, 78, 175, 99, 6, 111, 16, 103, 142, 61, 253, 224, 39, 52, 137, 252, 56, 116, 147, 71, 168, 16, 155, 245, 197, 97, 57, 69, 226, 13, 239, 164, 40, 228, 250, 130, 128, 186, 150, 3, 64, 81, 241, 165, 43, 136, 99, 79, 124, 188, 50, 46, 152, 197, 205, 204, 103, 254, 61, 143, 94, 31, 6, 98, 165, 16, 223, 175, 30, 87, 156, 176, 232, 56, 179, 56, 184, 220, 100, 141, 212, 201, 55, 246, 199, 117, 28, 154, 51, 140, 5, 95, 102, 187, 133, 248 }; auto test_uintwide_t_spot_values_from_issue_316_import_export_original() -> bool; auto test_uintwide_t_spot_values_from_issue_316_import_export_original() -> bool { // See also: https://github.com/ckormanyos/wide-integer/issues/316 #if defined(WIDE_INTEGER_NAMESPACE) using local_uint1024_t = WIDE_INTEGER_NAMESPACE::math::wide_integer::uint1024_t; #else using local_uint1024_t = ::math::wide_integer::uint1024_t; #endif auto result_is_ok = true; auto big_int = local_uint1024_t { }; import_bits(big_int, bin_128_source_of_bits_imported.cbegin(), bin_128_source_of_bits_imported.cend()); constexpr auto j = static_cast(INT8_C(50)); const auto big_int_50 = big_int + j; import_export_array_type out; for(auto i = static_cast(INT8_C(0)); i < j; ++i) { // Fill the output with erroneous values. out.fill(static_cast(UINT8_C(0x55))); ++big_int; static_cast ( export_bits ( big_int, out.begin(), static_cast ( std::numeric_limits::digits ) ) ); } const auto result_increment_and_export_is_ok = (big_int == big_int_50); import_bits(big_int, out.cbegin(), out.cend()); const auto result_increment_export_and_import_is_ok = (big_int == big_int_50); result_is_ok = ( result_increment_and_export_is_ok && result_increment_export_and_import_is_ok && result_is_ok); return result_is_ok; } auto test_uintwide_t_spot_values_from_issue_316_import_export_extended() -> bool; auto test_uintwide_t_spot_values_from_issue_316_import_export_extended() -> bool { // See also: https://github.com/ckormanyos/wide-integer/issues/316 import_export_array_type bin_128_made_from_bits_exported; #if defined(WIDE_INTEGER_NAMESPACE) using local_uint1024_t = WIDE_INTEGER_NAMESPACE::math::wide_integer::uint1024_t; #else using local_uint1024_t = ::math::wide_integer::uint1024_t; #endif local_uint1024_t val_made_from_bits_imported; auto result_is_ok = true; import_bits(val_made_from_bits_imported, bin_128_source_of_bits_imported.cbegin(), bin_128_source_of_bits_imported.cend()); static_cast ( export_bits ( val_made_from_bits_imported, bin_128_made_from_bits_exported.begin(), static_cast ( std::numeric_limits::digits ) ) ); const auto result_import_and_export_same_is_ok = std::equal(bin_128_source_of_bits_imported.cbegin(), bin_128_source_of_bits_imported.cend(), bin_128_made_from_bits_exported.cbegin()); result_is_ok = (result_import_and_export_same_is_ok && result_is_ok); return result_is_ok; } } // namespace from_issue_316 namespace from_issue_266 { auto test_uintwide_t_spot_values_from_issue_266_inc() -> bool; auto test_uintwide_t_spot_values_from_issue_266_inc() -> bool { // See also: https://github.com/ckormanyos/wide-integer/issues/266 #if defined(WIDE_INTEGER_NAMESPACE) using local_uint128_t = WIDE_INTEGER_NAMESPACE::math::wide_integer::uint128_t; #else using local_uint128_t = ::math::wide_integer::uint128_t; #endif local_uint128_t inc_value ("0x0000000000000001FFFFFFFFFFFFFFFF"); local_uint128_t inc_value_p(++(local_uint128_t(inc_value))); const auto result_is_ok = ((inc_value_p > inc_value) && (inc_value_p == local_uint128_t("0x00000000000000020000000000000000"))); return result_is_ok; } auto test_uintwide_t_spot_values_from_issue_266_dec() -> bool; auto test_uintwide_t_spot_values_from_issue_266_dec() -> bool { // See also: https://github.com/ckormanyos/wide-integer/issues/266 #if defined(WIDE_INTEGER_NAMESPACE) using local_uint128_t = WIDE_INTEGER_NAMESPACE::math::wide_integer::uint128_t; #else using local_uint128_t = ::math::wide_integer::uint128_t; #endif local_uint128_t dec_value ("0x00000000000000020000000000000000"); local_uint128_t dec_value_d(--(local_uint128_t(dec_value))); const auto result_is_ok = ((dec_value_d < dec_value) && (dec_value_d == local_uint128_t("0x0000000000000001FFFFFFFFFFFFFFFF"))); return result_is_ok; } } // namespace from_issue_266 namespace from_issue_234 { // See also https://github.com/ckormanyos/wide-integer/issues/234#issuecomment-1052960210 #if defined(WIDE_INTEGER_NAMESPACE) using uint80 = WIDE_INTEGER_NAMESPACE::math::wide_integer::uintwide_t(UINT32_C( 80)), std::uint16_t>; using uint512 = WIDE_INTEGER_NAMESPACE::math::wide_integer::uintwide_t(UINT32_C(512)), std::uint32_t>; #else using uint80 = ::math::wide_integer::uintwide_t(UINT32_C( 80)), std::uint16_t>; using uint512 = ::math::wide_integer::uintwide_t(UINT32_C(512)), std::uint32_t>; #endif constexpr auto convert_to_uint80(const uint512& value) -> uint80 { #if defined(WIDE_INTEGER_NAMESPACE) using WIDE_INTEGER_NAMESPACE::math::wide_integer::detail::make_lo; using WIDE_INTEGER_NAMESPACE::math::wide_integer::detail::make_hi; #else using ::math::wide_integer::detail::make_lo; using ::math::wide_integer::detail::make_hi; #endif static_assert(std::numeric_limits::digits * 2 == std::numeric_limits::digits, "Error: Wrong input/output limb types for this conversion"); using local_value_type = typename uint80::representation_type::value_type; return uint80::from_rep ( { #if defined(WIDE_INTEGER_NAMESPACE) make_lo(*WIDE_INTEGER_NAMESPACE::math::wide_integer::detail::advance_and_point(value.crepresentation().cbegin(), 0U)), make_hi(*WIDE_INTEGER_NAMESPACE::math::wide_integer::detail::advance_and_point(value.crepresentation().cbegin(), 0U)), make_lo(*WIDE_INTEGER_NAMESPACE::math::wide_integer::detail::advance_and_point(value.crepresentation().cbegin(), 1U)), make_hi(*WIDE_INTEGER_NAMESPACE::math::wide_integer::detail::advance_and_point(value.crepresentation().cbegin(), 1U)), make_lo(*WIDE_INTEGER_NAMESPACE::math::wide_integer::detail::advance_and_point(value.crepresentation().cbegin(), 2U)) #else make_lo(*::math::wide_integer::detail::advance_and_point(value.crepresentation().cbegin(), 0U)), make_hi(*::math::wide_integer::detail::advance_and_point(value.crepresentation().cbegin(), 0U)), make_lo(*::math::wide_integer::detail::advance_and_point(value.crepresentation().cbegin(), 1U)), make_hi(*::math::wide_integer::detail::advance_and_point(value.crepresentation().cbegin(), 1U)), make_lo(*::math::wide_integer::detail::advance_and_point(value.crepresentation().cbegin(), 2U)) #endif } ); } constexpr auto convert_to_uint512(const uint80& value) -> uint512 { #if defined(WIDE_INTEGER_NAMESPACE) using WIDE_INTEGER_NAMESPACE::math::wide_integer::detail::make_large; #else using ::math::wide_integer::detail::make_large; #endif static_assert(std::numeric_limits::digits * 2 == std::numeric_limits::digits, "Error: Wrong input/output limb types for this conversion"); using local_value_type = typename uint80::representation_type::value_type; return uint512::from_rep ( { #if defined(WIDE_INTEGER_NAMESPACE) make_large(*WIDE_INTEGER_NAMESPACE::math::wide_integer::detail::advance_and_point(value.crepresentation().cbegin(), 0U), *WIDE_INTEGER_NAMESPACE::math::wide_integer::detail::advance_and_point(value.crepresentation().cbegin(), 1U)), make_large(*WIDE_INTEGER_NAMESPACE::math::wide_integer::detail::advance_and_point(value.crepresentation().cbegin(), 2U), *WIDE_INTEGER_NAMESPACE::math::wide_integer::detail::advance_and_point(value.crepresentation().cbegin(), 3U)), make_large(*WIDE_INTEGER_NAMESPACE::math::wide_integer::detail::advance_and_point(value.crepresentation().cbegin(), 4U), #else make_large(*::math::wide_integer::detail::advance_and_point(value.crepresentation().cbegin(), 0U), *::math::wide_integer::detail::advance_and_point(value.crepresentation().cbegin(), 1U)), make_large(*::math::wide_integer::detail::advance_and_point(value.crepresentation().cbegin(), 2U), *::math::wide_integer::detail::advance_and_point(value.crepresentation().cbegin(), 3U)), make_large(*::math::wide_integer::detail::advance_and_point(value.crepresentation().cbegin(), 4U), #endif static_cast(0U)) } ); } } // namespace from_issue_234 namespace from_issue_145 { template auto test_uintwide_t_spot_values_from_issue_145(const UnknownIntegerType& x) -> bool { // See also https://github.com/ckormanyos/wide-integer/issues/145#issuecomment-1006374713 using local_unknown_integer_type = UnknownIntegerType; bool local_result_is_ok = true; #if (defined(__clang__) && (defined(__clang_major__) && (__clang_major__ > 6))) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wself-assign-overloaded" #endif { local_unknown_integer_type a = x; a += a; // NOLINT(clang-diagnostic-self-assign-overloaded) local_result_is_ok = ((a == (2U * x)) && local_result_is_ok); } { local_unknown_integer_type a = x; a -= a; // NOLINT(clang-diagnostic-self-assign-overloaded) local_result_is_ok = ((a == 0U) && local_result_is_ok); } { local_unknown_integer_type a = x; a /= a; // NOLINT(clang-diagnostic-self-assign-overloaded) local_result_is_ok = ((a == 1U) && local_result_is_ok); } #if (defined(__clang__) && (defined(__clang_major__) && (__clang_major__ > 6))) #pragma GCC diagnostic pop #endif return local_result_is_ok; } } // namespace from_issue_145 namespace from_pull_request_130 { template constexpr auto test_uintwide_t_spot_values_from_pull_request_130() -> bool { // See also https://github.com/ckormanyos/wide-integer/pull/130 using local_unknown_integer_type = UnknownIntegerType; using limits = std::numeric_limits; constexpr auto expected { -1 - limits::max() }; constexpr auto actual { limits::lowest() }; constexpr bool b_ok = (expected == actual); return b_ok; } } // namespace from_pull_request_130 namespace exercise_bad_string_input { auto test_uintwide_t_spot_values_exercise_bad_string_input() -> bool; auto test_uintwide_t_spot_values_exercise_bad_string_input() -> bool { #if defined(WIDE_INTEGER_NAMESPACE) using local_uint128_t = WIDE_INTEGER_NAMESPACE::math::wide_integer::uint128_t; #else using local_uint128_t = ::math::wide_integer::uint128_t; #endif local_uint128_t u1("bad-string-input"); local_uint128_t u2("0xEvenWorse"); const auto result_bad_string_u1_input_is_ok = (u1 == (std::numeric_limits::max)()); const auto result_bad_string_u2_input_is_ok = (u2 == (std::numeric_limits::max)()); const auto result_bad_string_input_is_ok = (result_bad_string_u1_input_is_ok && result_bad_string_u2_input_is_ok); return result_bad_string_input_is_ok; } } // namespace exercise_bad_string_input namespace exercise_pow_zero_one_two { auto test_uintwide_t_spot_values_exercise_pow_zero_one_two() -> bool; auto test_uintwide_t_spot_values_exercise_pow_zero_one_two() -> bool { #if defined(WIDE_INTEGER_NAMESPACE) using local_uint128_t = WIDE_INTEGER_NAMESPACE::math::wide_integer::uint128_t; #else using local_uint128_t = ::math::wide_integer::uint128_t; #endif local_uint128_t u(UINT64_C(9999999978787878)); using std::pow; local_uint128_t u0 = pow(u, 0); local_uint128_t u1 = pow(u, 1); local_uint128_t u2 = pow(u, 2); const bool result_pow_is_ok = ( (u0 == 1) && (u1 == u) && (u2 == u * u) ); return result_pow_is_ok; } } // namespace exercise_pow_zero_one_two namespace exercise_octal { auto test_uintwide_t_spot_values_exercise_octal() -> bool; auto test_uintwide_t_spot_values_exercise_octal() -> bool { #if defined(WIDE_INTEGER_NAMESPACE) using local_uint128_t = WIDE_INTEGER_NAMESPACE::math::wide_integer::uint128_t; #else using local_uint128_t = ::math::wide_integer::uint128_t; #endif constexpr local_uint128_t u_dec("100000000000000000000777772222211111"); constexpr local_uint128_t u_oct("0464114134543515404256122464446501262047"); auto result_conversion_is_ok = (u_dec == u_oct); static_assert(u_dec == u_oct, "Error: Conversion decimal to octal is not OK"); std::stringstream strm; strm << std::showbase << std::oct << u_oct; result_conversion_is_ok = ((strm.str() == "0464114134543515404256122464446501262047") && result_conversion_is_ok); return result_conversion_is_ok; } } // namespace exercise_octal namespace local_test_spot_values { auto test() -> bool; } // namespace local_test_spot_values auto local_test_spot_values::test() -> bool // NOLINT(readability-function-cognitive-complexity) { auto result_is_ok = true; { // See also: https://github.com/ckormanyos/wide-integer/issues/429 result_is_ok = (from_issue_429::test_uintwide_t_spot_values_from_issue_429() && result_is_ok); } { // See also: https://github.com/ckormanyos/wide-integer/issues/362 result_is_ok = (from_issue_362::test_uintwide_t_spot_values_from_issue_362() && result_is_ok); } { // See also: https://github.com/ckormanyos/wide-integer/issues/342 const auto result_from_issue_342_is_ok = ( from_issue_342::test_uintwide_t_spot_values_from_issue_342_pos() && from_issue_342::test_uintwide_t_spot_values_from_issue_342_mix()); result_is_ok = (result_from_issue_342_is_ok && result_is_ok); } { const auto result_from_issue_339_is_ok = from_issue_339::test_uintwide_t_spot_values_from_issue_339_underflow_2048_4096(); result_is_ok = (result_from_issue_339_is_ok && result_is_ok); } { result_is_ok = (exercise_bad_string_input::test_uintwide_t_spot_values_exercise_bad_string_input() && result_is_ok); } { result_is_ok = (exercise_pow_zero_one_two::test_uintwide_t_spot_values_exercise_pow_zero_one_two() && result_is_ok); } { result_is_ok = (exercise_octal::test_uintwide_t_spot_values_exercise_octal() && result_is_ok); } { // See also: https://github.com/ckormanyos/wide-integer/issues/316 result_is_ok = (from_issue_316::test_uintwide_t_spot_values_from_issue_316_import_export_original() && result_is_ok); result_is_ok = (from_issue_316::test_uintwide_t_spot_values_from_issue_316_import_export_extended() && result_is_ok); } { // See also: https://github.com/ckormanyos/wide-integer/issues/266 result_is_ok = (from_issue_266::test_uintwide_t_spot_values_from_issue_266_inc() && result_is_ok); result_is_ok = (from_issue_266::test_uintwide_t_spot_values_from_issue_266_dec() && result_is_ok); } { // See also: https://github.com/ckormanyos/wide-integer/issues/234#issuecomment-1053733496 #if defined(WIDE_INTEGER_NAMESPACE) using local_uint512_t = WIDE_INTEGER_NAMESPACE::math::wide_integer::uint512_t; using local_int512_t = WIDE_INTEGER_NAMESPACE::math::wide_integer::int512_t; #else using local_uint512_t = ::math::wide_integer::uint512_t; using local_int512_t = ::math::wide_integer::int512_t; #endif // BitOr[2^111, 31337] // 2596148429267413814265248164641385 local_int512_t value = 1; std::uint32_t to_shift = 111; // NOLINT(cppcoreguidelines-avoid-magic-numbers,readability-magic-numbers) local_uint512_t value2 = 31337; // NOLINT(cppcoreguidelines-avoid-magic-numbers,readability-magic-numbers) local_int512_t shift = (value << to_shift); value = shift | static_cast(value2); // ::math::wide_integer::int512_t | ::math::wide_integer::uint512_t result_is_ok = ((value == local_int512_t("2596148429267413814265248164641385")) && result_is_ok); } { // See also https://github.com/ckormanyos/wide-integer/issues/234#issuecomment-1052960210 constexpr from_issue_234::uint512 u512("0x123456780123456780"); constexpr from_issue_234::uint80 u80 = from_issue_234::convert_to_uint80(u512); const bool convert_512_to_80_is_ok = (u80 == from_issue_234::uint80("0x123456780123456780")); result_is_ok = (convert_512_to_80_is_ok && result_is_ok); static_assert(convert_512_to_80_is_ok, "Error: Converting 512-bit type to 80-bit type is not OK"); } { // See also https://github.com/ckormanyos/wide-integer/issues/234#issuecomment-1052960210 constexpr from_issue_234::uint80 u80("0x123456780123456780"); constexpr from_issue_234::uint512 u512 = from_issue_234::convert_to_uint512(u80); const bool convert_80_to_512_is_ok = (u512 == from_issue_234::uint512("0x123456780123456780")); static_assert(convert_80_to_512_is_ok, "Error: Converting 80-bit type to 512-bit type is not OK"); result_is_ok = (convert_80_to_512_is_ok && result_is_ok); } { // See also https://github.com/ckormanyos/wide-integer/issues/234 // In particular, how do I synthesize uint80_t? #if defined(WIDE_INTEGER_NAMESPACE) using local_uint80_type = WIDE_INTEGER_NAMESPACE::math::wide_integer::uintwide_t(UINT32_C(80)), std::uint16_t>; #else using local_uint80_type = ::math::wide_integer::uintwide_t(UINT32_C(80)), std::uint16_t>; #endif local_uint80_type u(123); // NOLINT(cppcoreguidelines-avoid-magic-numbers,readability-magic-numbers) local_uint80_type v(456); // NOLINT(cppcoreguidelines-avoid-magic-numbers,readability-magic-numbers) u *= u; // 15129 u *= u; // 228886641 u *= u; // 52389094428262881 result_is_ok = ((u == local_uint80_type("52389094428262881")) && result_is_ok); v *= v; // 207936 v *= v; // 43237380096 v *= v; // 1869471037565976969216 result_is_ok = ((v == local_uint80_type("1869471037565976969216")) && result_is_ok); const auto w = static_cast(v / u); result_is_ok = ((w == UINT16_C(35684)) && result_is_ok); } { // See also https://github.com/ckormanyos/wide-integer/issues/234 // In particular, how to find sint512_t.operator|(uint32_t). #if defined(WIDE_INTEGER_NAMESPACE) using local_sint512_type = WIDE_INTEGER_NAMESPACE::math::wide_integer::uintwide_t(UINT32_C(512)), std::uint32_t, void, true>; #else using local_sint512_type = ::math::wide_integer::uintwide_t(UINT32_C(512)), std::uint32_t, void, true>; #endif constexpr local_sint512_type u1("0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF55555555"); constexpr std::uint32_t v1 = UINT32_C(0xAAAAAAAA); constexpr local_sint512_type w1 = u1 | v1; constexpr local_sint512_type u2("0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF55555555"); constexpr std::uint32_t v2 = UINT32_C(0xAAAAAAAA); constexpr local_sint512_type w2 = v2 | u2; constexpr bool w1_is_ok = (w1 == (std::numeric_limits::max)()); constexpr bool w2_is_ok = (w2 == (std::numeric_limits::max)()); static_assert(w1_is_ok, "Error: Bitwise OR with built-in type is not OK"); static_assert(w2_is_ok, "Error: Bitwise OR with built-in type is not OK"); result_is_ok = (w1_is_ok && result_is_ok); result_is_ok = (w2_is_ok && result_is_ok); } { // See also https://github.com/ckormanyos/wide-integer/issues/213 #if defined(WIDE_INTEGER_NAMESPACE) using local_uint32_type = WIDE_INTEGER_NAMESPACE::math::wide_integer::uintwide_t(UINT32_C(32)), std::uint32_t, void, false>; #else using local_uint32_type = ::math::wide_integer::uintwide_t(UINT32_C(32)), std::uint32_t, void, false>; #endif constexpr local_uint32_type p ( static_cast(UINT8_C(61)) ); constexpr local_uint32_type q ( static_cast(UINT8_C(53)) ); constexpr local_uint32_type lcm_result = lcm(p - 1U, q - 1U); result_is_ok = ((static_cast(lcm_result) == static_cast(UINT16_C(780))) && result_is_ok); static_assert((static_cast(lcm_result) == static_cast(UINT16_C(780))), "Error: Rudimentary LCM calculation result is wrong"); } { // See also https://github.com/ckormanyos/wide-integer/issues/186 // Here we statically test non-explicit construction/conversion #if defined(WIDE_INTEGER_NAMESPACE) using local_uint128_type = WIDE_INTEGER_NAMESPACE::math::wide_integer::uintwide_t(UINT32_C(128)), std::uint32_t, void, false>; using local_int128_type = WIDE_INTEGER_NAMESPACE::math::wide_integer::uintwide_t(UINT32_C(128)), std::uint32_t, void, true>; using local_uint160_type = WIDE_INTEGER_NAMESPACE::math::wide_integer::uintwide_t(UINT32_C(160)), std::uint32_t, void, false>; using local_int160_type = WIDE_INTEGER_NAMESPACE::math::wide_integer::uintwide_t(UINT32_C(160)), std::uint32_t, void, true>; #else using local_uint128_type = ::math::wide_integer::uintwide_t(UINT32_C(128)), std::uint32_t, void, false>; using local_int128_type = ::math::wide_integer::uintwide_t(UINT32_C(128)), std::uint32_t, void, true>; using local_uint160_type = ::math::wide_integer::uintwide_t(UINT32_C(160)), std::uint32_t, void, false>; using local_int160_type = ::math::wide_integer::uintwide_t(UINT32_C(160)), std::uint32_t, void, true>; #endif // Static test of construction rules. // Various construction(s) static_assert(std::is_default_constructible ::value, "Error: Type is not default-constructible"); static_assert(std::is_default_constructible ::value, "Error: Type is not default-constructible"); static_assert(std::is_copy_constructible ::value, "Error: Type is not copy-constructible"); static_assert(std::is_copy_constructible ::value, "Error: Type is not copy-constructible"); static_assert(std::is_trivially_copy_constructible ::value, "Error: Type is not trivially copy-constructible"); static_assert(std::is_trivially_copy_constructible ::value, "Error: Type is not trivially copy-constructible"); static_assert(std::is_move_constructible ::value, "Error: Type is not move-constructible"); static_assert(std::is_move_constructible ::value, "Error: Type is not move-constructible"); static_assert(std::is_trivially_move_constructible ::value, "Error: Type is not trivially move-constructible"); static_assert(std::is_trivially_move_constructible ::value, "Error: Type is not trivially move-constructible"); // Constructible static_assert(std::is_trivially_constructible::value, "Error: Types are not trivially constructible"); static_assert(std::is_constructible ::value, "Error: Types are not constructible"); static_assert(std::is_constructible ::value, "Error: Types are not constructible"); static_assert(std::is_constructible ::value, "Error: Types are not constructible"); static_assert(std::is_constructible ::value, "Error: Types are not constructible"); static_assert(std::is_trivially_constructible::value, "Error: Types are not trivially constructible"); static_assert(std::is_constructible ::value, "Error: Types are not constructible"); static_assert(std::is_constructible ::value, "Error: Types are not constructible"); static_assert(std::is_constructible ::value, "Error: Types are not constructible"); static_assert(std::is_constructible ::value, "Error: Types are not constructible"); static_assert(std::is_trivially_constructible::value, "Error: Types are not trivially constructible"); static_assert(std::is_constructible ::value, "Error: Types are not constructible"); static_assert(std::is_constructible ::value, "Error: Types are not constructible"); static_assert(std::is_constructible ::value, "Error: Types are not constructible"); static_assert(std::is_constructible ::value, "Error: Types are not constructible"); static_assert(std::is_trivially_constructible::value, "Error: Types are not trivially constructible"); // Static test of conversion rules. static_assert(std::is_convertible::value, "Error: Types are not convertible"); static_assert(std::is_convertible::value, "Error: Types are not convertible"); static_assert(std::is_convertible::value, "Error: Types are not convertible"); static_assert(std::is_convertible::value, "Error: Types are not convertible"); static_assert(std::is_convertible::value, "Error: Types are not convertible"); static_assert(std::is_convertible::value, "Error: Types are not convertible"); static_assert(std::is_convertible::value, "Error: Types are not convertible"); static_assert(std::is_convertible::value, "Error: Types are not convertible"); static_assert(std::is_convertible::value, "Error: Types are not convertible"); static_assert(std::is_convertible::value, "Error: Types are not convertible"); static_assert(std::is_convertible::value, "Error: Types are not convertible"); static_assert(std::is_convertible::value, "Error: Types are not convertible"); } { // See also https://github.com/ckormanyos/wide-integer/issues/181 // Here we test explicit construction/conversion both statically // as well as dynamically (i.e., dynamically in run-time). #if defined(WIDE_INTEGER_NAMESPACE) using local_uint128_type = WIDE_INTEGER_NAMESPACE::math::wide_integer::uintwide_t(UINT32_C(128)), std::uint32_t, void, false>; using local_int128_type = WIDE_INTEGER_NAMESPACE::math::wide_integer::uintwide_t(UINT32_C(128)), std::uint32_t, void, true>; using local_uint160_type = WIDE_INTEGER_NAMESPACE::math::wide_integer::uintwide_t(UINT32_C(160)), std::uint32_t, void, false>; using local_int160_type = WIDE_INTEGER_NAMESPACE::math::wide_integer::uintwide_t(UINT32_C(160)), std::uint32_t, void, true>; #else using local_uint128_type = ::math::wide_integer::uintwide_t(UINT32_C(128)), std::uint32_t, void, false>; using local_int128_type = ::math::wide_integer::uintwide_t(UINT32_C(128)), std::uint32_t, void, true>; using local_uint160_type = ::math::wide_integer::uintwide_t(UINT32_C(160)), std::uint32_t, void, false>; using local_int160_type = ::math::wide_integer::uintwide_t(UINT32_C(160)), std::uint32_t, void, true>; #endif // Get randoms via: // RandomInteger[{100000000000000000000000000000000000, 10000000000000000000000000000000000000}] constexpr local_uint128_type u128_0("3076659267683009403742876678609501102"); constexpr local_uint128_type u128_1("9784355713321885697254484081284759103"); constexpr local_uint128_type u128_2("1759644461251476961796845209840363274"); constexpr auto u160_0 = local_uint160_type(u128_0); constexpr auto u160_1 = local_uint160_type(u128_1); constexpr auto u160_2 = local_uint160_type(u128_2); constexpr auto v128_0 = local_uint128_type(u160_0); constexpr auto v128_1 = local_uint128_type(u160_1); constexpr auto v128_2 = local_uint128_type(u160_2); result_is_ok = ((u128_0 == v128_0) && result_is_ok); result_is_ok = ((u128_1 == v128_1) && result_is_ok); result_is_ok = ((u128_2 == v128_2) && result_is_ok); static_assert(u128_0 == v128_0, "Error: Static check of inter-width casting (unsigned) is not OK"); static_assert(u128_1 == v128_1, "Error: Static check of inter-width casting (unsigned) is not OK"); static_assert(u128_2 == v128_2, "Error: Static check of inter-width casting (unsigned) is not OK"); constexpr local_int128_type n128_0("-3076659267683009403742876678609501102"); constexpr local_int128_type n128_1("-9784355713321885697254484081284759103"); constexpr local_int128_type n128_2("-1759644461251476961796845209840363274"); constexpr auto n160_0 = local_int160_type(n128_0); constexpr auto n160_1 = local_int160_type(n128_1); constexpr auto n160_2 = local_int160_type(n128_2); constexpr auto m128_0 = static_cast(n160_0); constexpr auto m128_1 = static_cast(n160_1); constexpr auto m128_2 = static_cast(n160_2); result_is_ok = ((n128_0 == m128_0) && result_is_ok); result_is_ok = ((n128_1 == m128_1) && result_is_ok); result_is_ok = ((n128_2 == m128_2) && result_is_ok); static_assert(u128_0 == v128_0, "Error: Static check of inter-width casting (signed) is not OK"); static_assert(u128_1 == v128_1, "Error: Static check of inter-width casting (signed) is not OK"); static_assert(u128_2 == v128_2, "Error: Static check of inter-width casting (signed) is not OK"); constexpr auto un160_0 = local_uint160_type(-n128_0); constexpr auto un160_1 = local_uint160_type(-n128_1); constexpr auto un160_2 = local_uint160_type(-n128_2); result_is_ok = ((un160_0 == u160_0) && result_is_ok); result_is_ok = ((un160_1 == u160_1) && result_is_ok); result_is_ok = ((un160_2 == u160_2) && result_is_ok); static_assert(un160_0 == u160_0, "Error: Static check of inter-width casting (mixed signes) is not OK"); static_assert(un160_1 == u160_1, "Error: Static check of inter-width casting (mixed signes) is not OK"); static_assert(un160_2 == u160_2, "Error: Static check of inter-width casting (mixed signes) is not OK"); constexpr auto s128_0 = local_int128_type(un160_0); constexpr auto s128_1 = local_int128_type(un160_1); constexpr auto s128_2 = local_int128_type(un160_2); result_is_ok = ((local_uint128_type(s128_0) == u128_0) && result_is_ok); result_is_ok = ((local_uint128_type(s128_1) == u128_1) && result_is_ok); result_is_ok = ((local_uint128_type(s128_2) == u128_2) && result_is_ok); static_assert(static_cast(s128_0) == u128_0, "Error: Static check of inter-width casting (mixed signes) is not OK"); static_assert(static_cast(s128_1) == u128_1, "Error: Static check of inter-width casting (mixed signes) is not OK"); static_assert(static_cast(s128_2) == u128_2, "Error: Static check of inter-width casting (mixed signes) is not OK"); } { // See also https://github.com/ckormanyos/wide-integer/issues/90 #if defined(WIDE_INTEGER_NAMESPACE) using WIDE_INTEGER_NAMESPACE::math::wide_integer::uint128_t; using WIDE_INTEGER_NAMESPACE::math::wide_integer::int128_t; #else using ::math::wide_integer::uint128_t; using ::math::wide_integer::int128_t; #endif // Get randoms via: // RandomInteger[{100000000000000000000000000000000000, 10000000000000000000000000000000000000}] { constexpr uint128_t u_sep("6'216'049'444'209'020'458'323'688'259'792'241'931"); constexpr uint128_t u ("6216049444209020458323688259792241931"); constexpr uint128_t n_sep("-3000'424'814'887'742'920'043'278'044'817'737'744"); constexpr uint128_t n ("-3000424814887742920043278044817737744"); // BaseForm[6216049444209020458323688259792241931, 16] // 4ad2ae64368b98a810635e9cd49850b_16 constexpr uint128_t h_sep("0x4'AD'2A'E6'43'68'B9'8A'81'06'35'E9'CD'49'85'0B"); result_is_ok = ((u_sep == u) && result_is_ok); result_is_ok = ((n_sep == n) && result_is_ok); result_is_ok = ((h_sep == u) && result_is_ok); static_assert(u_sep == u, "Error: Static check of construction via string with digit separators fails"); static_assert(n_sep == n, "Error: Static check of construction via string with digit separators fails"); static_assert(h_sep == u, "Error: Static check of construction via string with digit separators fails"); } } { // See also https://github.com/ckormanyos/wide-integer/issues/145#issuecomment-1006374713 #if defined(WIDE_INTEGER_NAMESPACE) using WIDE_INTEGER_NAMESPACE::math::wide_integer::uint128_t; using WIDE_INTEGER_NAMESPACE::math::wide_integer::int128_t; #else using ::math::wide_integer::uint128_t; using ::math::wide_integer::int128_t; #endif // Get randoms via: // RandomInteger[{100000000000000000000000000000000000, 10000000000000000000000000000000000000}] constexpr uint128_t u0("3076659267683009403742876678609501102"); constexpr uint128_t u1("9784355713321885697254484081284759103"); constexpr uint128_t u2("1759644461251476961796845209840363274"); result_is_ok = (from_issue_145::test_uintwide_t_spot_values_from_issue_145(u0) && result_is_ok); result_is_ok = (from_issue_145::test_uintwide_t_spot_values_from_issue_145(u1) && result_is_ok); result_is_ok = (from_issue_145::test_uintwide_t_spot_values_from_issue_145(u2) && result_is_ok); constexpr int128_t n0("-3076659267683009403742876678609501102"); constexpr int128_t n1("-9784355713321885697254484081284759103"); constexpr int128_t n2("-1759644461251476961796845209840363274"); result_is_ok = (from_issue_145::test_uintwide_t_spot_values_from_issue_145(n0) && result_is_ok); result_is_ok = (from_issue_145::test_uintwide_t_spot_values_from_issue_145(n1) && result_is_ok); result_is_ok = (from_issue_145::test_uintwide_t_spot_values_from_issue_145(n2) && result_is_ok); } { // See also https://github.com/ckormanyos/wide-integer/issues/154 { #if defined(WIDE_INTEGER_NAMESPACE) using local_uint64_type = WIDE_INTEGER_NAMESPACE::math::wide_integer::uint64_t; using local_uint128_type = WIDE_INTEGER_NAMESPACE::math::wide_integer::uint128_t; using local_uint512_type = WIDE_INTEGER_NAMESPACE::math::wide_integer::uint512_t; using local_uint1024_type = WIDE_INTEGER_NAMESPACE::math::wide_integer::uint1024_t; using local_uint2048_type = WIDE_INTEGER_NAMESPACE::math::wide_integer::uint2048_t; using local_uint4096_type = WIDE_INTEGER_NAMESPACE::math::wide_integer::uint4096_t; using local_uint8192_type = WIDE_INTEGER_NAMESPACE::math::wide_integer::uint8192_t; using local_uint16384_type = WIDE_INTEGER_NAMESPACE::math::wide_integer::uint16384_t; using local_uint32768_type = WIDE_INTEGER_NAMESPACE::math::wide_integer::uint32768_t; using local_uint65536_type = WIDE_INTEGER_NAMESPACE::math::wide_integer::uint65536_t; #else using local_uint64_type = ::math::wide_integer::uint64_t; using local_uint128_type = ::math::wide_integer::uint128_t; using local_uint512_type = ::math::wide_integer::uint512_t; using local_uint1024_type = ::math::wide_integer::uint1024_t; using local_uint2048_type = ::math::wide_integer::uint2048_t; using local_uint4096_type = ::math::wide_integer::uint4096_t; using local_uint8192_type = ::math::wide_integer::uint8192_t; using local_uint16384_type = ::math::wide_integer::uint16384_t; using local_uint32768_type = ::math::wide_integer::uint32768_t; using local_uint65536_type = ::math::wide_integer::uint65536_t; #endif static_assert((std::numeric_limits::max)() != 0U, "Error: Static check of convenience type fails"); static_assert((std::numeric_limits::max)() != 0U, "Error: Static check of convenience type fails"); static_assert((std::numeric_limits::max)() != 0U, "Error: Static check of convenience type fails"); static_assert((std::numeric_limits::max)() != 0U, "Error: Static check of convenience type fails"); static_assert((std::numeric_limits::max)() != 0U, "Error: Static check of convenience type fails"); static_assert((std::numeric_limits::max)() != 0U, "Error: Static check of convenience type fails"); static_assert((std::numeric_limits::max)() != 0U, "Error: Static check of convenience type fails"); static_assert((std::numeric_limits::max)() != 0U, "Error: Static check of convenience type fails"); static_assert((std::numeric_limits::max)() != 0U, "Error: Static check of convenience type fails"); static_assert((std::numeric_limits::max)() != 0U, "Error: Static check of convenience type fails"); static_assert((std::numeric_limits::min)() == 0U, "Error: Static check of convenience type fails"); static_assert((std::numeric_limits::min)() == 0U, "Error: Static check of convenience type fails"); static_assert((std::numeric_limits::min)() == 0U, "Error: Static check of convenience type fails"); static_assert((std::numeric_limits::min)() == 0U, "Error: Static check of convenience type fails"); static_assert((std::numeric_limits::min)() == 0U, "Error: Static check of convenience type fails"); static_assert((std::numeric_limits::min)() == 0U, "Error: Static check of convenience type fails"); static_assert((std::numeric_limits::min)() == 0U, "Error: Static check of convenience type fails"); static_assert((std::numeric_limits::min)() == 0U, "Error: Static check of convenience type fails"); static_assert((std::numeric_limits::min)() == 0U, "Error: Static check of convenience type fails"); static_assert((std::numeric_limits::min)() == 0U, "Error: Static check of convenience type fails"); } { #if defined(WIDE_INTEGER_NAMESPACE) using local_int64_type = WIDE_INTEGER_NAMESPACE::math::wide_integer::int64_t; using local_int128_type = WIDE_INTEGER_NAMESPACE::math::wide_integer::int128_t; using local_int512_type = WIDE_INTEGER_NAMESPACE::math::wide_integer::int512_t; using local_int1024_type = WIDE_INTEGER_NAMESPACE::math::wide_integer::int1024_t; using local_int2048_type = WIDE_INTEGER_NAMESPACE::math::wide_integer::int2048_t; using local_int4096_type = WIDE_INTEGER_NAMESPACE::math::wide_integer::int4096_t; using local_int8192_type = WIDE_INTEGER_NAMESPACE::math::wide_integer::int8192_t; using local_int16384_type = WIDE_INTEGER_NAMESPACE::math::wide_integer::int16384_t; using local_int32768_type = WIDE_INTEGER_NAMESPACE::math::wide_integer::int32768_t; using local_int65536_type = WIDE_INTEGER_NAMESPACE::math::wide_integer::int65536_t; #else using local_int64_type = ::math::wide_integer::int64_t; using local_int128_type = ::math::wide_integer::int128_t; using local_int512_type = ::math::wide_integer::int512_t; using local_int1024_type = ::math::wide_integer::int1024_t; using local_int2048_type = ::math::wide_integer::int2048_t; using local_int4096_type = ::math::wide_integer::int4096_t; using local_int8192_type = ::math::wide_integer::int8192_t; using local_int16384_type = ::math::wide_integer::int16384_t; using local_int32768_type = ::math::wide_integer::int32768_t; using local_int65536_type = ::math::wide_integer::int65536_t; #endif static_assert((std::numeric_limits::max)() != 0, "Error: Static check of convenience type fails"); static_assert((std::numeric_limits::max)() != 0, "Error: Static check of convenience type fails"); static_assert((std::numeric_limits::max)() != 0, "Error: Static check of convenience type fails"); static_assert((std::numeric_limits::max)() != 0, "Error: Static check of convenience type fails"); static_assert((std::numeric_limits::max)() != 0, "Error: Static check of convenience type fails"); static_assert((std::numeric_limits::max)() != 0, "Error: Static check of convenience type fails"); static_assert((std::numeric_limits::max)() != 0, "Error: Static check of convenience type fails"); static_assert((std::numeric_limits::max)() != 0, "Error: Static check of convenience type fails"); static_assert((std::numeric_limits::max)() != 0, "Error: Static check of convenience type fails"); static_assert((std::numeric_limits::max)() != 0, "Error: Static check of convenience type fails"); static_assert((std::numeric_limits::min)() != 0, "Error: Static check of convenience type fails"); static_assert((std::numeric_limits::min)() != 0, "Error: Static check of convenience type fails"); static_assert((std::numeric_limits::min)() != 0, "Error: Static check of convenience type fails"); static_assert((std::numeric_limits::min)() != 0, "Error: Static check of convenience type fails"); static_assert((std::numeric_limits::min)() != 0, "Error: Static check of convenience type fails"); static_assert((std::numeric_limits::min)() != 0, "Error: Static check of convenience type fails"); static_assert((std::numeric_limits::min)() != 0, "Error: Static check of convenience type fails"); static_assert((std::numeric_limits::min)() != 0, "Error: Static check of convenience type fails"); static_assert((std::numeric_limits::min)() != 0, "Error: Static check of convenience type fails"); static_assert((std::numeric_limits::min)() != 0, "Error: Static check of convenience type fails"); } { #if defined(WIDE_INTEGER_NAMESPACE) using local_uint131072_type = WIDE_INTEGER_NAMESPACE::math::wide_integer::uintwide_t(UINT32_C(131072)), std::uint32_t, std::allocator, false>; #else using local_uint131072_type = ::math::wide_integer::uintwide_t(UINT32_C(131072)), std::uint32_t, std::allocator, false>; #endif local_uint131072_type u(123U); // NOLINT(cppcoreguidelines-avoid-magic-numbers,readability-magic-numbers) local_uint131072_type v( 56U); // NOLINT(cppcoreguidelines-avoid-magic-numbers,readability-magic-numbers) // Multiply 123^256. u *= u; u *= u; u *= u; u *= u; u *= u; u *= u; u *= u; u *= u; // Multiply 56^256. v *= v; v *= v; v *= v; v *= v; v *= v; v *= v; v *= v; v *= v; { std::stringstream strm; // Divide 123^256 / 56^256 and verify the integral result. local_uint131072_type w = u / v; strm << w; result_is_ok = ((strm.str() == "3016988223108505362607102560314821693738482648596342283928988093842474437457679828842200") && result_is_ok); } } } { // See also https://github.com/ckormanyos/wide-integer/pull/130 // The exact issue motivating this PR turned out to be // an incorect report. The tests, however, are useful // and these have been integrated into _spot_values(). { #if defined(WIDE_INTEGER_NAMESPACE) using type = WIDE_INTEGER_NAMESPACE::math::wide_integer::uintwide_t(UINT32_C(64)), std::uint32_t, void, true>; #else using type = ::math::wide_integer::uintwide_t(UINT32_C(64)), std::uint32_t, void, true>; #endif result_is_ok = (from_pull_request_130::test_uintwide_t_spot_values_from_pull_request_130() && result_is_ok); static_assert(from_pull_request_130::test_uintwide_t_spot_values_from_pull_request_130(), "Error: Check conditions surrounding issue 130"); } { #if defined(WIDE_INTEGER_NAMESPACE) using type = WIDE_INTEGER_NAMESPACE::math::wide_integer::uintwide_t(UINT32_C(64)), std::uint8_t, void, true>; #else using type = ::math::wide_integer::uintwide_t(UINT32_C(64)), std::uint8_t, void, true>; #endif result_is_ok = (from_pull_request_130::test_uintwide_t_spot_values_from_pull_request_130() && result_is_ok); static_assert(from_pull_request_130::test_uintwide_t_spot_values_from_pull_request_130(), "Error: Check conditions surrounding issue 130"); } { #if defined(WIDE_INTEGER_NAMESPACE) using type = WIDE_INTEGER_NAMESPACE::math::wide_integer::uintwide_t(UINT32_C(256)), std::uint32_t, void, true>; #else using type = ::math::wide_integer::uintwide_t(UINT32_C(256)), std::uint32_t, void, true>; #endif result_is_ok = (from_pull_request_130::test_uintwide_t_spot_values_from_pull_request_130() && result_is_ok); static_assert(from_pull_request_130::test_uintwide_t_spot_values_from_pull_request_130(), "Error: Check conditions surrounding issue 130"); } { using type = std::int32_t; result_is_ok = (from_pull_request_130::test_uintwide_t_spot_values_from_pull_request_130() && result_is_ok); static_assert(from_pull_request_130::test_uintwide_t_spot_values_from_pull_request_130(), "Error: Check conditions surrounding issue 130"); } { using type = std::int64_t; result_is_ok = (from_pull_request_130::test_uintwide_t_spot_values_from_pull_request_130() && result_is_ok); static_assert(from_pull_request_130::test_uintwide_t_spot_values_from_pull_request_130(), "Error: Check conditions surrounding issue 130"); } } { #if defined(WIDE_INTEGER_NAMESPACE) using WIDE_INTEGER_NAMESPACE::math::wide_integer::uint256_t; #else using ::math::wide_integer::uint256_t; #endif // Consider: FromDigits["C9DD3EA24800F584CB28C25CC0E6FF1",16] // Expected control result: 16770224695321632575655872732632870897 constexpr uint256_t a("0xC9DD3EA24800F584CB28C25CC0E6FF1"); // Consider: FromDigits["1E934A2EEA60A2AD14ECCAE7AD82C069",16] // Expected control result: 40641612127094559121321599356729737321 constexpr uint256_t b("0x1E934A2EEA60A2AD14ECCAE7AD82C069"); constexpr auto v = b - 1U; constexpr auto lm = lcm(a - 1U, v); constexpr auto gd = gcd(a - 1U, v); // Consider: LCM[16770224695321632575655872732632870897 - 1, 40641612127094559121321599356729737321 - 1] result_is_ok = ((lm == uint256_t("28398706972978513348490390087175345493497748446743697820448222113648043280")) && result_is_ok); static_assert(lm == uint256_t("28398706972978513348490390087175345493497748446743697820448222113648043280"), "Error: Rudimentary LCM calculation result is wrong"); // Consiedr: GCD[16770224695321632575655872732632870897 - 1, 40641612127094559121321599356729737321 - 1] result_is_ok = ((gd == static_cast(UINT8_C(24))) && result_is_ok); static_assert(gd == static_cast(UINT8_C(24)), "Error: Rudimentary LCM calculation result is wrong"); { // Check GCD(0, v) to be equal to v (found mssing in code coverage analyses). using local_limb_type = typename uint256_t::limb_type; const auto gd0 = gcd(uint256_t(static_cast(UINT8_C(0))), v); result_is_ok = ((gd0 == v) && result_is_ok); } } { // See also https://github.com/ckormanyos/wide-integer/issues/111 { #if defined(WIDE_INTEGER_NAMESPACE) using WIDE_INTEGER_NAMESPACE::math::wide_integer::int256_t; #else using ::math::wide_integer::int256_t; #endif int256_t a("-578960446186580977117854925043439539266349923328202820197287920" "03956564819968"); int256_t a_itself = (std::numeric_limits::min)(); result_is_ok = ((a == (std::numeric_limits::min)()) && result_is_ok); int256_t b("1"); const int256_t a_div_b = a / b; result_is_ok = ((a_div_b == a) && result_is_ok); result_is_ok = ((a / a_itself == b) && result_is_ok); } { #if defined(WIDE_INTEGER_NAMESPACE) using my_int32_t = WIDE_INTEGER_NAMESPACE::math::wide_integer::uintwide_t(UINT32_C(32)), std::uint32_t, void, true>; #else using my_int32_t = ::math::wide_integer::uintwide_t(UINT32_C(32)), std::uint32_t, void, true>; #endif my_int32_t c("-2147483648"); // NOLINT(cppcoreguidelines-avoid-magic-numbers,readability-magic-numbers) my_int32_t c_itself = (std::numeric_limits::min)(); result_is_ok = ((c == (std::numeric_limits::min)()) && result_is_ok); my_int32_t d("1"); const my_int32_t c_div_d = c / d; result_is_ok = ((c / c_itself == d) && result_is_ok); result_is_ok = ((c_div_d == c) && result_is_ok); } } { // See also https://github.com/ckormanyos/wide-integer/issues/108 { #if defined(WIDE_INTEGER_NAMESPACE) using w_t = WIDE_INTEGER_NAMESPACE::math::wide_integer::uintwide_t(UINT32_C(32)), std::uint32_t, void, true>; using ww_t = WIDE_INTEGER_NAMESPACE::math::wide_integer::uintwide_t(UINT32_C(64)), std::uint32_t, void, true>; #else using w_t = ::math::wide_integer::uintwide_t(UINT32_C(32)), std::uint32_t, void, true>; using ww_t = ::math::wide_integer::uintwide_t(UINT32_C(64)), std::uint32_t, void, true>; #endif const w_t neg (-2); const ww_t neg_wide(-2); const ww_t neg_wide_cast(neg); std::string str_neg { }; std::string str_neg_wide { }; std::string str_neg_wide_cast { }; { std::stringstream strm; strm << neg; str_neg = strm.str(); } { std::stringstream strm; strm << neg_wide; str_neg_wide = strm.str(); } { std::stringstream strm; strm << neg_wide_cast; str_neg_wide_cast = strm.str(); } const bool result_neg_is_ok = (str_neg == "-2"); const bool result_neg_wide_is_ok = (str_neg_wide == "-2"); const bool result_neg_wide_cast_is_ok = (str_neg_wide_cast == "-2"); result_is_ok = (( result_neg_is_ok && result_neg_wide_is_ok && result_neg_wide_cast_is_ok) && result_is_ok); } { #if defined(WIDE_INTEGER_NAMESPACE) using w_t = WIDE_INTEGER_NAMESPACE::math::wide_integer::uintwide_t(UINT32_C(32)), std::uint8_t, void, true>; using ww_t = WIDE_INTEGER_NAMESPACE::math::wide_integer::uintwide_t(UINT32_C(64)), std::uint8_t, void, true>; #else using w_t = ::math::wide_integer::uintwide_t(UINT32_C(32)), std::uint8_t, void, true>; using ww_t = ::math::wide_integer::uintwide_t(UINT32_C(64)), std::uint8_t, void, true>; #endif const w_t neg (-2); const ww_t neg_wide(-2); const ww_t neg_wide_cast(neg); std::string str_neg { }; std::string str_neg_wide { }; std::string str_neg_wide_cast { }; { std::stringstream strm; strm << neg; str_neg = strm.str(); } { std::stringstream strm; strm << neg_wide; str_neg_wide = strm.str(); } { std::stringstream strm; strm << neg_wide_cast; str_neg_wide_cast = strm.str(); } const bool result_neg_is_ok = (str_neg == "-2"); const bool result_neg_wide_is_ok = (str_neg_wide == "-2"); const bool result_neg_wide_cast_is_ok = (str_neg_wide_cast == "-2"); result_is_ok = (( result_neg_is_ok && result_neg_wide_is_ok && result_neg_wide_cast_is_ok) && result_is_ok); } } { // See also https://github.com/ckormanyos/wide-integer/issues/63 constexpr auto input { #if defined(WIDE_INTEGER_NAMESPACE) WIDE_INTEGER_NAMESPACE::math::wide_integer::uintwide_t(UINT32_C(320)), std::uint32_t, void, true> #else ::math::wide_integer::uintwide_t(UINT32_C(320)), std::uint32_t, void, true> #endif { 1729348762983LL // NOLINT(cppcoreguidelines-avoid-magic-numbers,readability-magic-numbers) } }; constexpr bool result_ll_is_ok = (static_cast(input) == 1729348762983LL); // NOLINT(cppcoreguidelines-avoid-magic-numbers,readability-magic-numbers,google-runtime-int) static_assert(result_ll_is_ok, "Error: test_uintwide_t_spot_values unsigned not OK!"); result_is_ok = (result_ll_is_ok && result_is_ok); } { #if defined(WIDE_INTEGER_NAMESPACE) using WIDE_INTEGER_NAMESPACE::math::wide_integer::uint512_t; #else using ::math::wide_integer::uint512_t; #endif constexpr uint512_t a("698937339790347543053797400564366118744312537138445607919548628175822115805812983955794321304304417541511379093392776018867245622409026835324102460829431"); constexpr uint512_t b("100041341335406267530943777943625254875702684549707174207105689918734693139781"); constexpr uint512_t c = (a / b); constexpr uint512_t d = (a % b); // QuotientRemainder // Consider: [698937339790347543053797400564366118744312537138445607919548628175822115805812983955794321304304417541511379093392776018867245622409026835324102460829431, 100041341335406267530943777943625254875702684549707174207105689918734693139781] // Expected control result: {6986485091668619828842978360442127600954041171641881730123945989288792389271, 100041341335406267530943777943625254875702684549707174207105689918734693139780} constexpr bool c_is_ok = (c == "6986485091668619828842978360442127600954041171641881730123945989288792389271"); constexpr bool d_is_ok = (d == "100041341335406267530943777943625254875702684549707174207105689918734693139780"); result_is_ok = ((c_is_ok && d_is_ok) && result_is_ok); static_assert(c_is_ok, "Error: Static check of spot value division is not OK"); static_assert(d_is_ok, "Error: Static check of spot value remainder is not OK"); } { #if defined(WIDE_INTEGER_NAMESPACE) using WIDE_INTEGER_NAMESPACE::math::wide_integer::uint256_t; #else using ::math::wide_integer::uint256_t; #endif static_assert(std::numeric_limits::digits == 256, // NOLINT(cppcoreguidelines-avoid-magic-numbers,readability-magic-numbers) "Error: Incorrect digit count for this example"); // Note: Some of the comments in this file use the Wolfram Language(TM). // // Create two pseudo-random 256-bit unsigned integers. // Consider: Table[IntegerString[RandomInteger[(2^256) - 1], 16], 2] // // Expected control result: {F4DF741DE58BCB2F37F18372026EF9CBCFC456CB80AF54D53BDEED78410065DE, 166D63E0202B3D90ECCEAA046341AB504658F55B974A7FD63733ECF89DD0DF75} // // Set the values of two random 256-bit unsigned integers. // a = 0xF4DF741DE58BCB2F37F18372026EF9CBCFC456CB80AF54D53BDEED78410065DE // b = 0x166D63E0202B3D90ECCEAA046341AB504658F55B974A7FD63733ECF89DD0DF75 // // Multiply: // a * b = 0xE491A360C57EB4306C61F9A04F7F7D99BE3676AAD2D71C5592D5AE70F84AF076 // // Divide: // a / b = 10 // // Modulus: // a % b = 0x14998D5CA3DB6385F7DEDF4621DE48A9104AC13797C6567713D7ABC216D7AB4C constexpr uint256_t a("0xF4DF741DE58BCB2F37F18372026EF9CBCFC456CB80AF54D53BDEED78410065DE"); constexpr uint256_t b("0x166D63E0202B3D90ECCEAA046341AB504658F55B974A7FD63733ECF89DD0DF75"); constexpr uint256_t c("0xE491A360C57EB4306C61F9A04F7F7D99BE3676AAD2D71C5592D5AE70F84AF076"); constexpr auto result_mul_is_ok = ((a * b) == c); static_assert(result_mul_is_ok, "Error: Static check of spot value multiplication is not OK"); result_is_ok = (result_mul_is_ok && result_is_ok); constexpr uint256_t q(unsigned { UINT8_C(10) }); constexpr auto result_div_is_ok = ((a / b) == q); static_assert(result_div_is_ok, "Error: Static check of spot value division is not OK"); result_is_ok = (result_div_is_ok && result_is_ok); constexpr uint256_t m("0x14998D5CA3DB6385F7DEDF4621DE48A9104AC13797C6567713D7ABC216D7AB4C"); constexpr auto result_mod_is_ok = ((a % b) == m); static_assert(result_mod_is_ok, "Error: Static check of spot value modulus is not OK"); result_is_ok = (result_mod_is_ok && result_is_ok); { // See also: https://github.com/ckormanyos/wide-integer/issues/274 constexpr auto result_mod1_is_ok = ((a % int { INT8_C(1) }) == 0); constexpr auto result_mod7u_is_ok = ((a % unsigned { UINT8_C(7) }) == unsigned { UINT8_C(3) }); static_assert(result_mod1_is_ok, "Error: Static check of spot value modulus with 1 is not OK"); static_assert(result_mod7u_is_ok, "Error: Static check of spot value modulus with 7U is not OK"); result_is_ok = ((result_mod1_is_ok && result_mod7u_is_ok) && result_is_ok); } } return result_is_ok; } #if defined(WIDE_INTEGER_NAMESPACE) auto WIDE_INTEGER_NAMESPACE::math::wide_integer::test_uintwide_t_spot_values() -> bool // NOLINT(readability-function-cognitive-complexity) #else auto ::math::wide_integer::test_uintwide_t_spot_values() -> bool // NOLINT(readability-function-cognitive-complexity) #endif { return local_test_spot_values::test(); } ================================================ FILE: test/test_uintwide_t_xtra_from_issue_335.cpp ================================================ /////////////////////////////////////////////////////////////////////////////// // Copyright Christopher Kormanyos 2022 - 2025. // Distributed under the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt // or copy at http://www.boost.org/LICENSE_1_0.txt) // #include #include #include #if !defined(WIDE_INTEGER_DISABLE_PRIVATE_CLASS_DATA_MEMBERS) #define WIDE_INTEGER_DISABLE_PRIVATE_CLASS_DATA_MEMBERS #endif // cd /mnt/c/Users/User/Documents/Ks/PC_Software/NumericalPrograms/ExtendedNumberTypes/wide_integer // g++-10 -finline-functions -m64 -O3 -Werror -Wall -Wextra -Wconversion -Wsign-conversion -Wshadow -Wundef -Wunused-parameter -Wuninitialized -Wunreachable-code -Winit-self -Wzero-as-null-pointer-constant -std=c++20 -DWIDE_INTEGER_DISABLE_PRIVATE_CLASS_DATA_MEMBERS -DWIDE_INTEGER_NAMESPACE=ckormanyos -I. test/test_uintwide_t_xtra_from_issue_335.cpp -o test_uintwide_t_xtra_from_issue_335.exe #include namespace from_issue_335 { // See also: https://github.com/ckormanyos/wide-integer/issues/335 template(8U * sizeof(UInt)), UInt MaxValue = -UInt(1)> auto f(uint32_t n) -> std::string { std::stringstream strm; strm << BitCount << "-bit ; MaxValue = " << MaxValue << ", n = " << UInt(n); return strm.str(); } auto test_uintwide_t_xtra_from_issue_335() -> bool { #if defined(WIDE_INTEGER_NAMESPACE) using local_wide_integer_type = WIDE_INTEGER_NAMESPACE::math::wide_integer::uint256_t; #else using local_wide_integer_type = ::math::wide_integer::uint256_t; #endif // String result: // "256-bit ; MaxValue = 115792089237316195423570985008687907853269984665640564039457584007913129639935, n = 42" const auto str_result = f(42); std::cout << str_result << std::endl; const auto result_is_ok = ( str_result == "256-bit ; MaxValue = 115792089237316195423570985008687907853269984665640564039457584007913129639935, n = 42" ); return result_is_ok; } } auto main() -> int { const auto result_is_ok = from_issue_335::test_uintwide_t_xtra_from_issue_335(); std::cout << "result_is_ok: " << std::boolalpha << result_is_ok << std::endl; return (result_is_ok ? 0 : -1); } ================================================ FILE: util/utility/util_pseudorandom_time_point_seed.h ================================================ /////////////////////////////////////////////////////////////////////////////// // Copyright Christopher Kormanyos 2023 - 2025. // Distributed under the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt // or copy at http://www.boost.org/LICENSE_1_0.txt) // #ifndef UTIL_PSEUDORANDOM_TIME_POINT_SEED_2023_10_27_H // NOLINT(llvm-header-guard) #define UTIL_PSEUDORANDOM_TIME_POINT_SEED_2023_10_27_H #include #include #include #include #include #include #include #include #include namespace util { struct util_pseudorandom_time_point_seed { public: template static auto value() -> IntegralType { const std::uint64_t t_now { now() }; std::stringstream strm { }; using strtime_uint8_array_type = std::array(UINT8_C(16))>; strtime_uint8_array_type buf_u8 { }; buf_u8.fill(static_cast(UINT8_C(0))); // Get the string representation of the time point. strm << std::setw(std::tuple_size::value) << std::hex << std::uppercase << std::setfill('0') << t_now; const std::string str_tm { strm.str() }; std::copy(str_tm.cbegin(), str_tm.cend(), buf_u8.begin()); using local_integral_type = IntegralType; return static_cast(crc_crc64(buf_u8.data(), buf_u8.size())); } static constexpr auto test() noexcept -> bool; private: static auto now() -> std::uint64_t { #if defined(__CYGWIN__) return static_cast(std::clock()); #else // Get the time (t_now). timespec ts { }; static_cast(timespec_get(&ts, TIME_UTC)); return static_cast ( static_cast(static_cast(ts.tv_sec) * UINT64_C(1000000000)) + static_cast(ts.tv_nsec) ); #endif } template static constexpr auto crc_bitwise_template(const std::uint8_t* message, const std::size_t count, const UnsignedIntegralType polynomial, // NOLINT(bugprone-easily-swappable-parameters) const UnsignedIntegralType initial_value, const UnsignedIntegralType final_xor_value) -> UnsignedIntegralType { using value_type = UnsignedIntegralType; // The data_type is fixed to exactly 8-bits in width at the moment. using data_type = std::uint8_t; value_type crc = initial_value; // Perform the polynomial division, one element at a time. for(auto data_index = static_cast(UINT8_C(0)); data_index < count; ++data_index) { // Obtain the next data element (and reflect it if necessary). const data_type next_data_element = message[data_index]; // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) { constexpr auto left_shift_amount = static_cast ( std::numeric_limits::digits - std::numeric_limits::digits ); crc ^= static_cast(static_cast(next_data_element) << left_shift_amount); } // Process the next data byte, one bit at a time. for(std::uint_fast8_t index = 0U; index < static_cast(std::numeric_limits::digits); ++index) { const auto high_bit_value = static_cast ( crc & static_cast ( static_cast(UINT8_C(1)) << static_cast(std::numeric_limits::digits - 1) ) ); const bool high_bit_of_crc_is_set = (high_bit_value != static_cast(UINT8_C(0))); crc = crc << static_cast(UINT8_C(1)); if(high_bit_of_crc_is_set) { // Shift through the polynomial. Also left-justify the // polynomial within the width of value_type, if necessary. crc ^= static_cast(polynomial); } } } // Perform the final XOR on the result. crc ^= final_xor_value; return crc; } static constexpr auto crc_crc64(const std::uint8_t* message, const std::size_t count) -> std::uint64_t { // check: 0x6C40DF5F0B497347 return crc_bitwise_template(UINT8_C(64)), std::uint64_t> ( message, count, static_cast(UINT64_C(0x42F0E1EBA9EA3693)), static_cast(UINT64_C(0x0000000000000000)), static_cast(UINT64_C(0x0000000000000000)) ); } }; constexpr auto util_pseudorandom_time_point_seed::test() noexcept -> bool { using crc64_test_data_array_type = std::array; constexpr crc64_test_data_array_type crc64_test_data = {{ 0x31U, 0x32U, 0x33U, 0x34U, 0x35U, 0x36U, 0x37U, 0x38U, 0x39U }}; constexpr auto crc64_test_result = crc_bitwise_template(UINT8_C(64)), std::uint64_t> ( &crc64_test_data[std::size_t { UINT8_C(0) }], std::tuple_size::value, static_cast(UINT64_C(0x42F0E1EBA9EA3693)), static_cast(UINT64_C(0x0000000000000000)), static_cast(UINT64_C(0x0000000000000000)) ); // check: 0x6C40DF5F0B497347 return (crc64_test_result == static_cast(UINT64_C(0x6C40DF5F0B497347))); } static_assert(util::util_pseudorandom_time_point_seed::test(), "Error: crc64 implementation is not working properly"); } // namespace util #endif // UTIL_PSEUDORANDOM_TIME_POINT_SEED_2023_10_27_H ================================================ FILE: wide_integer.sln ================================================  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 15 VisualStudioVersion = 15.0.28010.2036 MinimumVisualStudioVersion = 10.0.40219.1 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "wide_integer", "wide_integer.vcxproj", "{3D16BABC-0908-40AB-AFF2-FD60B9172A5B}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|x64 = Debug|x64 Debug|x86 = Debug|x86 Release|x64 = Release|x64 Release|x86 = Release|x86 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {3D16BABC-0908-40AB-AFF2-FD60B9172A5B}.Debug|x64.ActiveCfg = Debug|x64 {3D16BABC-0908-40AB-AFF2-FD60B9172A5B}.Debug|x64.Build.0 = Debug|x64 {3D16BABC-0908-40AB-AFF2-FD60B9172A5B}.Debug|x86.ActiveCfg = Debug|Win32 {3D16BABC-0908-40AB-AFF2-FD60B9172A5B}.Debug|x86.Build.0 = Debug|Win32 {3D16BABC-0908-40AB-AFF2-FD60B9172A5B}.Release|x64.ActiveCfg = Release|x64 {3D16BABC-0908-40AB-AFF2-FD60B9172A5B}.Release|x64.Build.0 = Release|x64 {3D16BABC-0908-40AB-AFF2-FD60B9172A5B}.Release|x86.ActiveCfg = Release|Win32 {3D16BABC-0908-40AB-AFF2-FD60B9172A5B}.Release|x86.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {23A7720B-5B7B-4E07-92C8-F66F79D7E0C0} EndGlobalSection EndGlobal ================================================ FILE: wide_integer.vcxproj ================================================ Debug Win32 Release Win32 Debug x64 Release x64 15.0 {3D16BABC-0908-40AB-AFF2-FD60B9172A5B} Win32Proj wideinteger 10.0 Application true v142 NotSet Application false v142 true NotSet Application true v142 NotSet Application false v142 true NotSet true $(ProjectDir);C:\boost\boost_1_85_0;$(IncludePath) true $(ProjectDir);C:\boost\boost_1_90_0;$(IncludePath) false $(ProjectDir);C:\boost\boost_1_85_0;$(IncludePath) false $(ProjectDir);C:\boost\boost_1_90_0;$(IncludePath) NotUsing Level4 Disabled true WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) true 4996 stdcpplatest /bigobj true Console true NotUsing Level4 Disabled true _DEBUG;_CONSOLE;%(PreprocessorDefinitions) true 4996 stdcpplatest /bigobj true Console true NotUsing Level4 MaxSpeed true true true WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) true Speed 4996 stdcpplatest /bigobj true Console true true true NotUsing Level4 MaxSpeed true true true NDEBUG;_CONSOLE;%(PreprocessorDefinitions) true Speed 4996 stdcpplatest /bigobj true Console true true true true true true true true true true true true true true true true true true true true true true true true true true true true true true true true true true true ================================================ FILE: wide_integer.vcxproj.filters ================================================  {4FC737F1-C7A5-4376-A066-2A32D752A2FF} cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx {2ab8711c-4632-4af5-8345-b408e6ed36bb} {48a97642-b509-4ac8-b6d5-6a19a897bacf} {340a3a17-d99f-441d-abba-fc9db2aaafa9} {249d1a53-43c3-4a48-9fb9-c3a477ddf025} {038c20dc-264e-432d-9c1d-d92bea2d31ed} {26852f75-5102-4d51-a876-48fadc8bc7dc} {2fd84722-7a2f-490d-80e6-9961207cee67} {7ea96594-9256-4fd5-8e0e-04b187aa45c3} {8460bf03-d727-4c68-8f29-e2acf7b95386} {ceebef52-f03f-4437-8256-8bf8301cf498} {c8663027-03cc-43d3-a3bc-927bbbdb3b3f} {d3d4d6ad-0796-4bd5-b015-cd9c948caccf} {09bf1894-26c1-40a4-870e-f338f0940b7b} {78812fa7-c747-46fb-861d-bb6cfe3070ab} {5e008254-9733-4d69-99e2-8d2f93c4b374} {67bbe456-ef04-4dd3-8fbe-d20ffe14c2dc} {27be7d17-0d98-431e-bea5-96948075efef} {0bfd6ce7-a9b6-4847-9b45-f4cd69735e04} {e181fa1c-901d-4680-9c9b-62a576f135d2} {083f53f0-1b7d-4be6-8adf-c6a9ab7671c1} {24de4171-df89-40f3-87b7-3dfdee251467} {81934cc8-18b6-4dc9-8558-f5adcec3bf99} {5995e678-0e77-4d1b-b881-ef1ada7cb408} Source Files\boost\multiprecision Source Files\test Source Files\test Source Files\test Source Files\test Source Files\test Source Files\test Source Files\test Source Files\math\wide_integer Source Files\test Source Files\test Source Files\examples Source Files\test Source Files\test Source Files\util\utility Source Files\test Source Files\examples Source Files\examples Source Files\examples Source Files\examples Source Files\examples Source Files\examples Source Files\examples Source Files\examples Source Files\examples Source Files\test Source Files\test Source Files\examples Source Files\examples Source Files\test Source Files\examples Source Files\test Source Files\examples Source Files\test Source Files\test Source Files\examples Source Files\examples Source Files\examples Source Files\examples Source Files\examples Source Files\test Source Files\test Source Files\examples Source Files\examples Source Files\test Source Files\test target\micros\stm32f429\make\single Source Files\test Source Files\examples Source Files\examples Source Files\examples .github\workflows _doc .tidy\make .tidy\make .tidy\make .github\workflows .gcov\make .gcov\make .gcov\make .github\workflows .props target\micros\stm32f429\make target\build Source Files\examples\build .github\workflows Source Files\examples Source Files\test ================================================ FILE: wide_integer_vs2022.sln ================================================  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 17 VisualStudioVersion = 17.2.32519.379 MinimumVisualStudioVersion = 10.0.40219.1 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "wide_integer_vs2022", "wide_integer_vs2022.vcxproj", "{3D16BABC-0908-40AB-AFF2-FD60B9172A5B}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|x64 = Debug|x64 Debug|x86 = Debug|x86 Release|x64 = Release|x64 Release|x86 = Release|x86 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {3D16BABC-0908-40AB-AFF2-FD60B9172A5B}.Debug|x64.ActiveCfg = Debug|x64 {3D16BABC-0908-40AB-AFF2-FD60B9172A5B}.Debug|x64.Build.0 = Debug|x64 {3D16BABC-0908-40AB-AFF2-FD60B9172A5B}.Debug|x86.ActiveCfg = Debug|Win32 {3D16BABC-0908-40AB-AFF2-FD60B9172A5B}.Debug|x86.Build.0 = Debug|Win32 {3D16BABC-0908-40AB-AFF2-FD60B9172A5B}.Release|x64.ActiveCfg = Release|x64 {3D16BABC-0908-40AB-AFF2-FD60B9172A5B}.Release|x64.Build.0 = Release|x64 {3D16BABC-0908-40AB-AFF2-FD60B9172A5B}.Release|x86.ActiveCfg = Release|Win32 {3D16BABC-0908-40AB-AFF2-FD60B9172A5B}.Release|x86.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {23A7720B-5B7B-4E07-92C8-F66F79D7E0C0} EndGlobalSection EndGlobal ================================================ FILE: wide_integer_vs2022.vcxproj ================================================ Debug Win32 Release Win32 Debug x64 Release x64 15.0 {3D16BABC-0908-40AB-AFF2-FD60B9172A5B} Win32Proj wideinteger 10.0 wide_integer_vs2022 Application true v143 NotSet Application false v143 true NotSet Application true v143 NotSet Application false v143 true NotSet true $(ProjectDir);C:\boost\boost_1_88_0;$(IncludePath) true $(ProjectDir);C:\boost\boost_1_90_0;$(IncludePath) false $(ProjectDir);C:\boost\boost_1_88_0;$(IncludePath) false $(ProjectDir);C:\boost\boost_1_90_0;$(IncludePath) NotUsing Level4 Disabled true WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) true 4996 stdcpp20 /bigobj true stdc11 Console true NotUsing Level4 Disabled true _DEBUG;_CONSOLE;%(PreprocessorDefinitions) true 4996 stdcpp20 /bigobj true stdc11 Console true NotUsing Level4 MaxSpeed true true true WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) true Speed 4996 stdcpp20 /bigobj true stdc11 Console true true true NotUsing Level4 MaxSpeed true true true NDEBUG;_CONSOLE;%(PreprocessorDefinitions) true Speed 4996 stdcpp20 /bigobj true stdc11 Console true true true true true true true true true true true true true true true true true true true true true true true true true true true true true true true true true true true true true true true true true true true true true true true true true true true true true true true true true true true true true true true true true ================================================ FILE: wide_integer_vs2022.vcxproj.filters ================================================  {4FC737F1-C7A5-4376-A066-2A32D752A2FF} cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx {2ab8711c-4632-4af5-8345-b408e6ed36bb} {48a97642-b509-4ac8-b6d5-6a19a897bacf} {340a3a17-d99f-441d-abba-fc9db2aaafa9} {249d1a53-43c3-4a48-9fb9-c3a477ddf025} {038c20dc-264e-432d-9c1d-d92bea2d31ed} {26852f75-5102-4d51-a876-48fadc8bc7dc} {2fd84722-7a2f-490d-80e6-9961207cee67} {7ea96594-9256-4fd5-8e0e-04b187aa45c3} {8460bf03-d727-4c68-8f29-e2acf7b95386} {ceebef52-f03f-4437-8256-8bf8301cf498} {c8663027-03cc-43d3-a3bc-927bbbdb3b3f} {d3d4d6ad-0796-4bd5-b015-cd9c948caccf} {09bf1894-26c1-40a4-870e-f338f0940b7b} {6e3f5c2f-92fc-41d4-ac03-2821505331c0} {0cfae90f-72ab-4f83-8fa7-2265a8abf5d5} {8fcd7c05-1f4e-436c-87ca-3b1e998b7b67} {9439d123-c5a3-4434-bf7a-bed02e95fb0d} {43cc559c-46e6-4ba2-a6e6-f3e29fc3cf42} {d00c386f-1e4f-4741-8c73-e2c26bc38edb} {876be41b-c9a3-4a46-bc46-8624178094fd} {d0da75c7-dd48-4e37-b1ee-283464e3ce9d} {597ab5f0-b045-443a-8da2-1b929052b42f} Source Files\boost\multiprecision Source Files\test Source Files\test Source Files\test Source Files\test Source Files\test Source Files\test Source Files\test Source Files\math\wide_integer Source Files\test Source Files\test Source Files\examples Source Files\test Source Files\test Source Files\util\utility Source Files\test Source Files\test Source Files\examples Source Files\examples Source Files\examples Source Files\examples Source Files\examples Source Files\examples Source Files\examples Source Files\examples Source Files\examples Source Files\test Source Files\test Source Files\examples Source Files\examples Source Files\test Source Files\examples Source Files\test Source Files\examples Source Files\test Source Files\test Source Files\examples Source Files\examples Source Files\examples Source Files\examples Source Files\examples Source Files\test Source Files\test Source Files\examples Source Files\examples Source Files\test Source Files\test target\micros\stm32f429\make\single Source Files\test Source Files\examples Source Files\examples Source Files\test\fuzzing Source Files\test\fuzzing Source Files\test\fuzzing Source Files\test\fuzzing Source Files\test\fuzzing Source Files\test\fuzzing Source Files\test\fuzzing Source Files\test\fuzzing Source Files\test\fuzzing Source Files\examples .github\workflows _doc .tidy\make .tidy\make .tidy\make .github\workflows .gcov\make .gcov\make .gcov\make .github\workflows target\build target\micros\stm32f429\make .github\workflows .github\workflows Source Files\examples Source Files\test