diff -Nru primesieve-6.3+ds/ChangeLog primesieve-7.0+ds/ChangeLog --- primesieve-6.3+ds/ChangeLog 2017-11-18 12:38:21.000000000 +0000 +++ primesieve-7.0+ds/ChangeLog 2018-06-08 08:51:41.000000000 +0000 @@ -1,3 +1,54 @@ +Changes in version 7.0, 25/04/2018 +================================== + +This is a major new release, the API is backwards compatible but the +ABI (Application binary interface) is not backwards compatible. + +primesieve's core algorithms have been rewritten using next_prime() +instead of callbacks. The benefit of this redesign is a much improved +primesieve::iterator that runs up to twice as fast and uses only +half as much memory as before! + + * primesieve::iterator: Faster next_prime(). + * primesieve::iterator: Cache small primes in lookup table. + * PrimeGenerator.cpp: Incrementally store primes in a vector. + * StorePrimes.hpp: Use primesieve::iterator instead of callbacks. + * SievingPrimes.hpp: Use next_prime() instead of callbacks. + * Reduce number of memory allocations by up to 30%. + * Modernize code base using C++11. + * Test suite runs up to twice as fast. + +## Breaking ABI Changes: + +New variables have been added to the C++ primesieve::iterator class +and the C primesieve_iterator struct. Users that have written +primesieve bindings for other programming languages are affected +by these ABI changes and need to update their code. + +Changes in version 6.4, 23/03/2018 +================================== + +This is a minor new release, the API and ABI are backwards compatible. + + * Switch to https: https://primesieve.org. + * Faster printing to stdout. + * Required CMake version is now 3.4 (previously 3.1) + * CMakeLists.txt: Support find_package(primesieve). + * CMakeLists.txt: Add Fedora multiarch support. + * CMakeLists.txt: Fix libatomic detection. + * CMakeLists.txt: Fix make install issue. + * calculator.hpp: Fix integer overflow. + * test/calculator.cpp: Add test for expression parser. + +## Breaking Changes: + +The 2 changes below may potentially break the build of projects that +have hardcoded the src/primesieve path and/or the +src/primesieve/README filename in their build script. + + * Move libprimesieve sources from ./src/primesieve to ./src. + * Rename src/primesieve/README to src/README.md. + Changes in version 6.3, 12/11/2017 ================================== @@ -511,7 +562,7 @@ only 12 asm instructions (previously 16). 4. Improved OpenMP load balance in src/soe/ParallelPrimeSieve.cpp. 5. Improved code readability of EratSmall.cpp, EratMedium.cpp, - EratBig.cpp, SieveOfEratosthenes.cpp and others. + EratBig.cpp, Erat.cpp and others. 6. The Makefile now automatically detects the CPU's L1 data cache size on Unix-like OSes (Linux, Mac OS X). 7. Renamed ./docs to ./doc @@ -535,7 +586,7 @@ 4. New template imath.h functions: isqrt(), ilog2(), isPow2(), ... isqrt() has been rewritten using Newton's algorithm in order to avoid rounding errors of (int)sqrt((double)n) if n > 10^15. - 5. New internal SieveOfEratosthenes::getNextPrime(...) member function. + 5. New internal Erat::getNextPrime(...) member function. 6. Replaced old C-style comments with C++ comments. 7. Updated ExpressionParser to version 2.2. 8. uin32_t has been replaced by uint_t in src/soe/*. diff -Nru primesieve-6.3+ds/cmake/primesieveConfig.cmake.in primesieve-7.0+ds/cmake/primesieveConfig.cmake.in --- primesieve-6.3+ds/cmake/primesieveConfig.cmake.in 1970-01-01 00:00:00.000000000 +0000 +++ primesieve-7.0+ds/cmake/primesieveConfig.cmake.in 2018-06-08 08:51:41.000000000 +0000 @@ -0,0 +1,39 @@ +# ==================================================================== +# The primesieve CMake configuration file +# +# Usage from an external project: +# In your CMakeLists.txt, add these lines: +# +# find_package(primesieve REQUIRED) +# target_link_libraries(your_target primesieve::primesieve) +# +# To link against the static libprimesieve use: +# +# find_package(primesieve REQUIRED static) +# target_link_libraries(your_target primesieve::primesieve) +# +# ==================================================================== + +include(CMakeFindDependencyMacro) +find_dependency(Threads QUIET) + +if(@BUILD_STATIC_LIBS@ AND @BUILD_SHARED_LIBS@) + if(primesieve_FIND_COMPONENTS) + string(TOLOWER "${primesieve_FIND_COMPONENTS}" LOWER_COMPONENTS) + if(LOWER_COMPONENTS STREQUAL "static") + set(primesieve_STATIC TRUE) + endif() + endif() +elseif(@BUILD_STATIC_LIBS@) + set(primesieve_STATIC TRUE) +endif() + +if(primesieve_STATIC) + include("${CMAKE_CURRENT_LIST_DIR}/primesieveStatic.cmake") + add_library(primesieve::primesieve INTERFACE IMPORTED) + set_target_properties(primesieve::primesieve PROPERTIES INTERFACE_LINK_LIBRARIES "primesieve::libprimesieve-static") +else() + include("${CMAKE_CURRENT_LIST_DIR}/primesieveShared.cmake") + add_library(primesieve::primesieve INTERFACE IMPORTED) + set_target_properties(primesieve::primesieve PROPERTIES INTERFACE_LINK_LIBRARIES "primesieve::libprimesieve") +endif() diff -Nru primesieve-6.3+ds/CMakeLists.txt primesieve-7.0+ds/CMakeLists.txt --- primesieve-6.3+ds/CMakeLists.txt 2017-11-18 12:38:21.000000000 +0000 +++ primesieve-7.0+ds/CMakeLists.txt 2018-06-08 08:51:41.000000000 +0000 @@ -1,8 +1,7 @@ -cmake_minimum_required(VERSION 3.1) -project(primesieve) -set(PRIMESIEVE_VERSION "6.3") -set(PRIMESIEVE_SOVERSION "8.3.0") -set(CMAKE_BUILD_TYPE Release) +cmake_minimum_required(VERSION 3.4) +project(primesieve CXX) +set(PRIMESIEVE_VERSION "7.0") +set(PRIMESIEVE_SOVERSION "9.0.0") # Build options ###################################################### @@ -17,10 +16,9 @@ set(BUILD_SHARED_LIBS OFF) endif() -# Compiler must support C++11 or later ############################### - -set(CMAKE_CXX_STANDARD 11) -set(CMAKE_CXX_STANDARD_REQUIRED ON) +if(NOT BUILD_SHARED_LIBS AND NOT BUILD_STATIC_LIBS) + message(FATAL_ERROR "One or both of BUILD_SHARED_LIBS or BUILD_STATIC_LIBS must be set to ON") +endif() # primesieve binary source files ##################################### @@ -30,103 +28,172 @@ # primesieve library source files #################################### -set(LIB_SRC src/primesieve/api-c.cpp - src/primesieve/api.cpp - src/primesieve/CpuInfo.cpp - src/primesieve/EratBig.cpp - src/primesieve/EratMedium.cpp - src/primesieve/EratSmall.cpp - src/primesieve/iterator-c.cpp - src/primesieve/iterator.cpp - src/primesieve/nthPrime.cpp - src/primesieve/ParallelPrimeSieve.cpp - src/primesieve/popcount.cpp - src/primesieve/PreSieve.cpp - src/primesieve/PrimeGenerator.cpp - src/primesieve/PrimeSieve.cpp - src/primesieve/SieveOfEratosthenes.cpp - src/primesieve/SievingPrimes.cpp - src/primesieve/Wheel.cpp) +set(LIB_SRC src/api-c.cpp + src/api.cpp + src/CpuInfo.cpp + src/EratBig.cpp + src/EratMedium.cpp + src/EratSmall.cpp + src/iterator-c.cpp + src/iterator.cpp + src/IteratorHelper.cpp + src/PrimeGenerator.cpp + src/nthPrime.cpp + src/ParallelSieve.cpp + src/popcount.cpp + src/PreSieve.cpp + src/PrintPrimes.cpp + src/PrimeSieve.cpp + src/Erat.cpp + src/SievingPrimes.cpp + src/Wheel.cpp) -# Silence GCC switch fall through warnings ########################### +# Required includes ################################################## +include(GNUInstallDirs) +include(CMakePushCheckState) include(CheckCXXCompilerFlag) -check_cxx_compiler_flag(-Wno-implicit-fallthrough no_fallthrough) +include(CheckCXXSourceCompiles) +include(CMakePackageConfigHelpers) + +# Set default build type to Release ################################## + +if(NOT CMAKE_BUILD_TYPE) + set(CMAKE_BUILD_TYPE "Release" CACHE STRING + "Choose the type of build, options are: None Debug Release RelWithDebInfo MinSizeRel." + FORCE) +endif() + +# Silence GCC switch fall through warnings ########################### + +check_cxx_compiler_flag(-Wno-implicit-fallthrough Wno_fallthrough) -if(no_fallthrough) - set_source_files_properties(src/primesieve/EratSmall.cpp PROPERTIES COMPILE_FLAGS -Wno-implicit-fallthrough) +if(Wno_fallthrough) + set_source_files_properties(src/EratSmall.cpp PROPERTIES COMPILE_FLAGS -Wno-implicit-fallthrough) endif() # Check if libatomic is needed ####################################### -include(CheckCXXSourceCompiles) +cmake_push_check_state() -set(CMAKE_OLD_FLAGS ${CMAKE_REQUIRED_FLAGS}) -set(CMAKE_REQUIRED_FLAGS ${CMAKE_CXX11_STANDARD_COMPILE_OPTION}) +if(CMAKE_CXX11_STANDARD_COMPILE_OPTION) + set(CMAKE_REQUIRED_FLAGS ${CMAKE_CXX11_STANDARD_COMPILE_OPTION}) +endif() check_cxx_source_compiles(" #include + #include int main() { - std::atomic x; + std::atomic x; x = 1; x--; - return x; + return (int) x; }" - have_atomic) + atomic64) -set(CMAKE_REQUIRED_FLAGS ${CMAKE_OLD_FLAGS}) +if(NOT atomic64) + find_library(ATOMIC NAMES atomic libatomic.so.1) -if(NOT have_atomic) - find_library(ATOMIC NAMES atomic libatomic.so libatomic.so.1) if(ATOMIC) set(LIBATOMIC ${ATOMIC}) - message(STATUS "Found libatomic: TRUE") + message(STATUS "Found libatomic: ${LIBATOMIC}") + else() + check_cxx_source_compiles(" + #include + #include + int main() { + std::atomic x; + x = 1; + x--; + return (int) x; + }" + atomic32) + + if(atomic32) + message(FATAL_ERROR "Failed to find libatomic!") + endif() endif() endif() -# libprimesieve ###################################################### +cmake_pop_check_state() -add_library(libprimesieve ${LIB_SRC}) -set_target_properties(libprimesieve PROPERTIES OUTPUT_NAME primesieve) -find_package(Threads REQUIRED) -target_link_libraries(libprimesieve Threads::Threads ${LIBATOMIC}) - -target_include_directories(libprimesieve PUBLIC - $ - $) +# libprimesieve (shared library) ##################################### + +find_package(Threads REQUIRED QUIET) if(BUILD_SHARED_LIBS) + add_library(libprimesieve SHARED ${LIB_SRC}) + add_library(primesieve::primesieve ALIAS libprimesieve) + set_target_properties(libprimesieve PROPERTIES OUTPUT_NAME primesieve) + target_link_libraries(libprimesieve PRIVATE Threads::Threads ${LIBATOMIC}) + string(REPLACE "." ";" SOVERSION_LIST ${PRIMESIEVE_SOVERSION}) list(GET SOVERSION_LIST 0 PRIMESIEVE_SOVERSION_MAJOR) set_target_properties(libprimesieve PROPERTIES SOVERSION ${PRIMESIEVE_SOVERSION_MAJOR}) set_target_properties(libprimesieve PROPERTIES VERSION ${PRIMESIEVE_SOVERSION}) + + target_compile_features(libprimesieve + PUBLIC + cxx_alias_templates + PRIVATE + cxx_constexpr + cxx_uniform_initialization + cxx_lambdas) + + target_include_directories(libprimesieve PUBLIC + $ + $) + + install(TARGETS libprimesieve + EXPORT primesieveShared + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) endif() -install(TARGETS libprimesieve - DESTINATION ${CMAKE_INSTALL_PREFIX}/lib/${CMAKE_LIBRARY_ARCHITECTURE}) +# libprimesieve-static ############################################### -# static_libprimesieve ############################################### +if(BUILD_STATIC_LIBS) + add_library(libprimesieve-static STATIC ${LIB_SRC}) + set_target_properties(libprimesieve-static PROPERTIES OUTPUT_NAME primesieve) + target_link_libraries(libprimesieve-static PRIVATE Threads::Threads ${LIBATOMIC}) + + if(BUILD_SHARED_LIBS) + add_dependencies(libprimesieve-static libprimesieve) + else() + add_library(primesieve::primesieve ALIAS libprimesieve-static) + endif() -if(BUILD_STATIC_LIBS AND BUILD_SHARED_LIBS) - add_library(static_libprimesieve STATIC ${LIB_SRC}) - set_target_properties(static_libprimesieve PROPERTIES OUTPUT_NAME primesieve) - target_link_libraries(static_libprimesieve Threads::Threads ${LIBATOMIC}) + target_compile_features(libprimesieve-static + PUBLIC + cxx_alias_templates + PRIVATE + cxx_constexpr + cxx_uniform_initialization + cxx_lambdas) - target_include_directories(static_libprimesieve PUBLIC + target_include_directories(libprimesieve-static PUBLIC $ $) - install(TARGETS static_libprimesieve - DESTINATION ${CMAKE_INSTALL_PREFIX}/lib/${CMAKE_LIBRARY_ARCHITECTURE}) + install(TARGETS libprimesieve-static + EXPORT primesieveStatic + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) endif() # primesieve binary ################################################## if(BUILD_PRIMESIEVE) add_executable(primesieve ${BIN_SRC}) - target_link_libraries(primesieve libprimesieve) - install(TARGETS primesieve - DESTINATION ${CMAKE_INSTALL_PREFIX}/bin) + target_link_libraries(primesieve primesieve::primesieve) + target_compile_features(primesieve PRIVATE cxx_auto_type) + install(TARGETS primesieve DESTINATION ${CMAKE_INSTALL_BINDIR}) + + if(BUILD_STATIC_LIBS) + add_dependencies(primesieve libprimesieve-static) + endif() endif() # Install headers #################################################### @@ -134,16 +201,42 @@ install(FILES include/primesieve.h include/primesieve.hpp COMPONENT libprimesieve-headers - DESTINATION ${CMAKE_INSTALL_PREFIX}/include) + DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) -install(FILES include/primesieve/PrimeSieve.hpp - include/primesieve/StorePrimes.hpp - include/primesieve/iterator.h +install(FILES include/primesieve/iterator.h include/primesieve/iterator.hpp + include/primesieve/StorePrimes.hpp include/primesieve/primesieve_error.hpp - include/primesieve/pmath.hpp COMPONENT libprimesieve-headers - DESTINATION ${CMAKE_INSTALL_PREFIX}/include/primesieve) + DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/primesieve) + +# CMake find_package(primesieve) support ############################# + +write_basic_package_version_file( + "${CMAKE_CURRENT_BINARY_DIR}/primesieveConfigVersion.cmake" + VERSION ${PRIMESIEVE_VERSION} + COMPATIBILITY SameMajorVersion) + +configure_package_config_file( + "${PROJECT_SOURCE_DIR}/cmake/primesieveConfig.cmake.in" + "${CMAKE_CURRENT_BINARY_DIR}/primesieveConfig.cmake" + INSTALL_DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/primesieve") + +install(FILES "${CMAKE_CURRENT_BINARY_DIR}/primesieveConfig.cmake" + "${CMAKE_CURRENT_BINARY_DIR}/primesieveConfigVersion.cmake" + DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/primesieve") + +if(BUILD_SHARED_LIBS) + install(EXPORT primesieveShared + NAMESPACE primesieve:: + DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/primesieve") +endif() + +if(BUILD_STATIC_LIBS) + install(EXPORT primesieveStatic + NAMESPACE primesieve:: + DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/primesieve") +endif() # Regenerate man page ################################################ @@ -181,15 +274,15 @@ if(BUILD_PRIMESIEVE) install(FILES ${PROJECT_SOURCE_DIR}/doc/primesieve.1 - DESTINATION ${CMAKE_INSTALL_PREFIX}/share/man/man1) + DESTINATION ${CMAKE_INSTALL_MANDIR}/man1) endif() # Install primesieve.pc (pkg-config) ################################# configure_file(primesieve.pc.in primesieve.pc @ONLY) -install(FILES ${CMAKE_BINARY_DIR}/primesieve.pc - DESTINATION ${CMAKE_INSTALL_PREFIX}/lib/${CMAKE_LIBRARY_ARCHITECTURE}/pkgconfig) +install(FILES ${CMAKE_CURRENT_BINARY_DIR}/primesieve.pc + DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig) # Add subdirectories ################################################# diff -Nru primesieve-6.3+ds/COPYING primesieve-7.0+ds/COPYING --- primesieve-6.3+ds/COPYING 2017-11-18 12:38:21.000000000 +0000 +++ primesieve-7.0+ds/COPYING 2018-06-08 08:51:41.000000000 +0000 @@ -1,6 +1,6 @@ BSD 2-Clause License -Copyright (c) 2010 - 2017, Kim Walisch. +Copyright (c) 2010 - 2018, Kim Walisch. All rights reserved. Redistribution and use in source and binary forms, with or without diff -Nru primesieve-6.3+ds/debian/changelog primesieve-7.0+ds/debian/changelog --- primesieve-6.3+ds/debian/changelog 2018-01-26 08:35:27.000000000 +0000 +++ primesieve-7.0+ds/debian/changelog 2018-06-18 14:36:25.000000000 +0000 @@ -1,9 +1,47 @@ -primesieve (6.3+ds-2ubuntu1) bionic; urgency=medium +primesieve (7.0+ds-3ubuntu1) cosmic; urgency=medium - * Allow stderr output in autpkgtests to ignore - * notes emitted by GCC7 on armhf + * Allow stderr output in autopkgtests for GCC warnings on armhf - -- Graham Inggs Fri, 26 Jan 2018 08:35:27 +0000 + -- Graham Inggs Mon, 18 Jun 2018 14:36:25 +0000 + +primesieve (7.0+ds-3) unstable; urgency=medium + + * RC bug fix release (Closes: #901128), bump library so-suffix. + * autopkgtests bug fix post-release (Closes: #901098). + * Debianization: + - debian/{control,rules}: + - library so-suffix, bump to 9. + + -- Jerome Benoit Sat, 09 Jun 2018 07:08:21 +0000 + +primesieve (7.0+ds-2) unstable; urgency=medium + + * autopkgtests bug fix release. + * Debianization: + - debian/tests/*: + - d/t/make-check-dev , refresh. + + -- Jerome Benoit Sat, 09 Jun 2018 06:06:25 +0000 + +primesieve (7.0+ds-1) unstable; urgency=medium + + * New upstream major release. + * Debianization: + - debian/copyright: + - Format field, secure URI; + - debian/control: + - Standards Version, bump to 4.1.4 (no change); + - Homepage field, secure URI; + - Vcs-* fields, migration to Salsa; + - debian/source: + - d/s/lintian-overrides , update; + - debian/rules: + - get-orig-source target, discard; + - README.implementation.md target, refresh (cascade change); + - debian/patches: + - d/p/upstream-fix-cmake_machinery-libatomic.patch , integrated. + + -- Jerome Benoit Fri, 08 Jun 2018 09:28:07 +0000 primesieve (6.3+ds-2) unstable; urgency=medium diff -Nru primesieve-6.3+ds/debian/control primesieve-7.0+ds/debian/control --- primesieve-6.3+ds/debian/control 2018-01-26 08:35:27.000000000 +0000 +++ primesieve-7.0+ds/debian/control 2018-06-18 14:36:25.000000000 +0000 @@ -10,10 +10,10 @@ Build-Depends-Indep: doxygen, doxygen-latex, graphviz, rdfind, symlinks -Standards-Version: 4.1.3 -Vcs-Browser: https://anonscm.debian.org/cgit/debian-science/packages/primesieve.git -Vcs-Git: https://anonscm.debian.org/git/debian-science/packages/primesieve.git -Homepage: http://primesieve.org/ +Standards-Version: 4.1.4 +Vcs-Git: https://salsa.debian.org/science-team/primesieve.git +Vcs-Browser: https://salsa.debian.org/science-team/primesieve +Homepage: https://primesieve.org/ Package: primesieve Architecture: any @@ -27,7 +27,7 @@ . This dummy package provides the standard installation. -Package: libprimesieve8 +Package: libprimesieve9 Architecture: any Multi-Arch: same Section: libs @@ -50,7 +50,7 @@ Multi-Arch: same Section: libdevel Depends: - libprimesieve8 (= ${binary:Version}), libprimesieve-dev-common (= ${source:Version}), + libprimesieve9 (= ${binary:Version}), libprimesieve-dev-common (= ${source:Version}), ${misc:Depends} Suggests: primesieve-doc (= ${source:Version}), pkg-config Conflicts: libprimesieve-dev diff -Nru primesieve-6.3+ds/debian/copyright primesieve-7.0+ds/debian/copyright --- primesieve-6.3+ds/debian/copyright 2018-01-06 07:43:36.000000000 +0000 +++ primesieve-7.0+ds/debian/copyright 2018-06-08 09:15:24.000000000 +0000 @@ -1,4 +1,4 @@ -Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0 +Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0 Upstream-Name: primesieve Upstream-Contact: Kim Walisch Source: http://primesieve.org/downloads/ diff -Nru primesieve-6.3+ds/debian/libprimesieve8.docs primesieve-7.0+ds/debian/libprimesieve8.docs --- primesieve-6.3+ds/debian/libprimesieve8.docs 2015-11-10 17:29:58.000000000 +0000 +++ primesieve-7.0+ds/debian/libprimesieve8.docs 1970-01-01 00:00:00.000000000 +0000 @@ -1,2 +0,0 @@ -README.md -README.implementation diff -Nru primesieve-6.3+ds/debian/libprimesieve8.install primesieve-7.0+ds/debian/libprimesieve8.install --- primesieve-6.3+ds/debian/libprimesieve8.install 2015-11-10 17:29:58.000000000 +0000 +++ primesieve-7.0+ds/debian/libprimesieve8.install 1970-01-01 00:00:00.000000000 +0000 @@ -1 +0,0 @@ -usr/lib/*/libprimesieve.so.* diff -Nru primesieve-6.3+ds/debian/libprimesieve8.lintian-overrides primesieve-7.0+ds/debian/libprimesieve8.lintian-overrides --- primesieve-6.3+ds/debian/libprimesieve8.lintian-overrides 2016-08-04 15:00:35.000000000 +0000 +++ primesieve-7.0+ds/debian/libprimesieve8.lintian-overrides 1970-01-01 00:00:00.000000000 +0000 @@ -1,2 +0,0 @@ -# the upstream source contains C++ code with an intricate (and non-human) ABI -no-symbols-control-file diff -Nru primesieve-6.3+ds/debian/libprimesieve9.docs primesieve-7.0+ds/debian/libprimesieve9.docs --- primesieve-6.3+ds/debian/libprimesieve9.docs 1970-01-01 00:00:00.000000000 +0000 +++ primesieve-7.0+ds/debian/libprimesieve9.docs 2018-06-08 09:07:37.000000000 +0000 @@ -0,0 +1,2 @@ +README.md +README.implementation.md diff -Nru primesieve-6.3+ds/debian/libprimesieve9.install primesieve-7.0+ds/debian/libprimesieve9.install --- primesieve-6.3+ds/debian/libprimesieve9.install 1970-01-01 00:00:00.000000000 +0000 +++ primesieve-7.0+ds/debian/libprimesieve9.install 2015-11-10 17:29:58.000000000 +0000 @@ -0,0 +1 @@ +usr/lib/*/libprimesieve.so.* diff -Nru primesieve-6.3+ds/debian/libprimesieve9.lintian-overrides primesieve-7.0+ds/debian/libprimesieve9.lintian-overrides --- primesieve-6.3+ds/debian/libprimesieve9.lintian-overrides 1970-01-01 00:00:00.000000000 +0000 +++ primesieve-7.0+ds/debian/libprimesieve9.lintian-overrides 2016-08-04 15:00:35.000000000 +0000 @@ -0,0 +1,2 @@ +# the upstream source contains C++ code with an intricate (and non-human) ABI +no-symbols-control-file diff -Nru primesieve-6.3+ds/debian/libprimesieve-dev-common.docs primesieve-7.0+ds/debian/libprimesieve-dev-common.docs --- primesieve-6.3+ds/debian/libprimesieve-dev-common.docs 2015-11-10 17:29:58.000000000 +0000 +++ primesieve-7.0+ds/debian/libprimesieve-dev-common.docs 2018-06-08 09:09:09.000000000 +0000 @@ -1,2 +1,2 @@ README.md -README.implementation +README.implementation.md diff -Nru primesieve-6.3+ds/debian/patches/series primesieve-7.0+ds/debian/patches/series --- primesieve-6.3+ds/debian/patches/series 2017-11-24 13:32:36.000000000 +0000 +++ primesieve-7.0+ds/debian/patches/series 1970-01-01 00:00:00.000000000 +0000 @@ -1 +0,0 @@ -upstream-fix-cmake_machinery-libatomic.patch diff -Nru primesieve-6.3+ds/debian/patches/upstream-fix-cmake_machinery-libatomic.patch primesieve-7.0+ds/debian/patches/upstream-fix-cmake_machinery-libatomic.patch --- primesieve-6.3+ds/debian/patches/upstream-fix-cmake_machinery-libatomic.patch 2017-11-24 13:40:58.000000000 +0000 +++ primesieve-7.0+ds/debian/patches/upstream-fix-cmake_machinery-libatomic.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,22 +0,0 @@ -Description: fix: cmake machinery: libatomic support - Correct the check process for C++ atomic support as suggested by - the upstream maintainer [1]. - [1] https://github.com/kimwalisch/primesieve/issues/45 -Origin: vendor, Debian -Forwarded: not-needed -Author: Jerome Benoit -Last-Update: 2017-11-24 - ---- a/CMakeLists.txt -+++ b/CMakeLists.txt -@@ -66,8 +66,9 @@ - - check_cxx_source_compiles(" - #include -+ #include - int main() { -- std::atomic x; -+ std::atomic x; - x = 1; - x--; - return x; diff -Nru primesieve-6.3+ds/debian/primesieve-doc.docs primesieve-7.0+ds/debian/primesieve-doc.docs --- primesieve-6.3+ds/debian/primesieve-doc.docs 2015-11-10 17:29:58.000000000 +0000 +++ primesieve-7.0+ds/debian/primesieve-doc.docs 2018-06-08 09:10:57.000000000 +0000 @@ -1,4 +1,4 @@ README.md -README.implementation +README.implementation.md _build/DEBIAN/doc/latex/primesieve_refman.pdf _build/DEBIAN/doc/html diff -Nru primesieve-6.3+ds/debian/rules primesieve-7.0+ds/debian/rules --- primesieve-6.3+ds/debian/rules 2017-11-18 13:17:14.000000000 +0000 +++ primesieve-7.0+ds/debian/rules 2018-06-09 07:04:46.000000000 +0000 @@ -29,13 +29,13 @@ -DBUILD_EXAMPLES=ON \ -DBUILD_DOC=ON -override_dh_auto_build-indep: README.implementation +override_dh_auto_build-indep: README.implementation.md $(MAKE) -f debian/adhoc/Makefile doc override_dh_auto_test-indep: true -override_dh_prep-arch: README.implementation +override_dh_prep-arch: README.implementation.md override_dh_auto_install-indep: DESTDIR=$(CURDIR)/debian/tmp $(CMAKE) \ @@ -43,7 +43,7 @@ -P _build/cmake_install.cmake override_dh_installdocs: - dh_installdocs -pprimesieve-bin --link-doc=libprimesieve8 + dh_installdocs -pprimesieve-bin --link-doc=libprimesieve9 dh_installdocs -plibprimesieve-dev --doc-main-package=libprimesieve-dev-common dh_installdocs --remaining-packages @@ -53,10 +53,7 @@ override_dh_compress-indep: dh_compress -X.pdf -Xexamples -get-orig-source: - uscan --no-conf --download-current-version --verbose - -README.implementation: - cp -p src/primesieve/README README.implementation +README.implementation.md: + cp -p src/README.md README.implementation.md CMAKE ?= cmake diff -Nru primesieve-6.3+ds/debian/source/lintian-overrides primesieve-7.0+ds/debian/source/lintian-overrides --- primesieve-6.3+ds/debian/source/lintian-overrides 2015-11-10 17:29:58.000000000 +0000 +++ primesieve-7.0+ds/debian/source/lintian-overrides 2018-06-08 09:15:46.000000000 +0000 @@ -1,3 +1,3 @@ # the upstream source tarball is not (yet) signed: request to the upstream author # was sent -- Jerome Benoit -debian-watch-may-check-gpg-signature +debian-watch-does-not-check-gpg-signature diff -Nru primesieve-6.3+ds/debian/tests/make-check-dev primesieve-7.0+ds/debian/tests/make-check-dev --- primesieve-6.3+ds/debian/tests/make-check-dev 2018-01-06 12:44:09.000000000 +0000 +++ primesieve-7.0+ds/debian/tests/make-check-dev 2018-06-09 06:01:48.000000000 +0000 @@ -6,7 +6,9 @@ mkdir -p $ADTTMP/include/primesieve cp -vpd -t $ADTTMP/include/primesieve include/primesieve/PrimeSieve.hpp -cp -vpd -t $ADTTMP/include/primesieve include/primesieve/ParallelPrimeSieve.hpp +cp -vpd -t $ADTTMP/include/primesieve include/primesieve/ParallelSieve.hpp +cp -vpd -t $ADTTMP/include/primesieve include/primesieve/pmath.hpp +cp -vpd -t $ADTTMP/include/primesieve include/primesieve/calculator.hpp cp -vpd -t $ADTTMP/tests test/*.c cp -vpd -t $ADTTMP/tests test/*.cpp diff -Nru primesieve-6.3+ds/doc/CMakeLists.txt primesieve-7.0+ds/doc/CMakeLists.txt --- primesieve-6.3+ds/doc/CMakeLists.txt 2017-11-18 12:38:21.000000000 +0000 +++ primesieve-7.0+ds/doc/CMakeLists.txt 2018-06-08 08:51:41.000000000 +0000 @@ -2,13 +2,14 @@ if(DOXYGEN_FOUND) find_package(LATEX) + find_program(DOT_FONUD dot) + if(LATEX_COMPILER) set(HAVE_LATEX "YES") else() set(HAVE_LATEX "NO") endif() - find_program(DOT_FONUD dot) if(DOT_FONUD) message(STATUS "Found dot (graphviz): ${DOT_FONUD}") set(HAVE_DOT "YES") diff -Nru primesieve-6.3+ds/doc/mainpage.dox primesieve-7.0+ds/doc/mainpage.dox --- primesieve-6.3+ds/doc/mainpage.dox 2017-11-18 12:38:21.000000000 +0000 +++ primesieve-7.0+ds/doc/mainpage.dox 2018-06-08 08:51:41.000000000 +0000 @@ -8,23 +8,23 @@ /// requirement is about pi(sqrt(n)) * 8 bytes per thread, its /// run-time complexity is O(n log log n) operations. The recommended /// way to get started is to first have a look at a few C or C++ -/// example programs. The most common use cases are storing primes in -/// a vector (or array) and iterating over primes using next_prime() -/// or prev_prime(). +/// example programs. The most common use cases are iterating over +/// primes using next_prime() or prev_prime() and storing primes in +/// a vector or an array. /// -/// For more information please visit http://primesieve.org. +/// For more information please visit https://primesieve.org. /// /// @section CPP_API C++ API /// /// @li @link primesieve.hpp primesieve.hpp @endlink - primesieve C++ header. -/// @li @link store_primes_in_vector.cpp store_primes_in_vector.cpp @endlink - Example that shows how to store primes in a std::vector. /// @li @link primesieve_iterator.cpp primesieve_iterator.cpp @endlink - Example that shows how to iterate over primes using primesieve::iterator. +/// @li @link store_primes_in_vector.cpp store_primes_in_vector.cpp @endlink - Example that shows how to store primes in a std::vector. /// @li @link count_primes.cpp count_primes.cpp @endlink - Example that shows how to count primes. /// /// @section C_API C API /// /// @li @link primesieve.h primesieve.h @endlink - primesieve C header. -/// @li @link store_primes_in_array.c store_primes_in_array.c @endlink - Example that shows how to store primes in an array. /// @li @link primesieve_iterator.c primesieve_iterator.c @endlink - Example that shows how to iterate over primes using @link iterator.h primesieve_iterator @endlink. +/// @li @link store_primes_in_array.c store_primes_in_array.c @endlink - Example that shows how to store primes in an array. /// @li @link count_primes.c count_primes.c @endlink - Example that shows how to count primes. /// diff -Nru primesieve-6.3+ds/examples/c/CMakeLists.txt primesieve-7.0+ds/examples/c/CMakeLists.txt --- primesieve-6.3+ds/examples/c/CMakeLists.txt 2017-11-18 12:38:21.000000000 +0000 +++ primesieve-7.0+ds/examples/c/CMakeLists.txt 2018-06-08 08:51:41.000000000 +0000 @@ -1,6 +1,8 @@ +enable_language(C) file(GLOB files "*.c") + foreach(file ${files}) get_filename_component(binary_name ${file} NAME_WE) add_executable(${binary_name}_c ${file}) - target_link_libraries(${binary_name}_c libprimesieve) + target_link_libraries(${binary_name}_c primesieve::primesieve) endforeach() diff -Nru primesieve-6.3+ds/examples/c/nth_prime.c primesieve-7.0+ds/examples/c/nth_prime.c --- primesieve-6.3+ds/examples/c/nth_prime.c 2017-11-18 12:38:21.000000000 +0000 +++ primesieve-7.0+ds/examples/c/nth_prime.c 2018-06-08 08:51:41.000000000 +0000 @@ -9,7 +9,8 @@ int main(int argc, char** argv) { uint64_t n = 1000; - if (argv[1]) + + if (argc > 1 && argv[1]) n = atol(argv[1]); uint64_t prime = primesieve_nth_prime(n, 0); diff -Nru primesieve-6.3+ds/examples/c/prev_prime.c primesieve-7.0+ds/examples/c/prev_prime.c --- primesieve-6.3+ds/examples/c/prev_prime.c 2017-11-18 12:38:21.000000000 +0000 +++ primesieve-7.0+ds/examples/c/prev_prime.c 2018-06-08 08:51:41.000000000 +0000 @@ -14,10 +14,11 @@ primesieve_skipto(&it, 2000, 1000); uint64_t prime; - /* iterate over the primes from 2000 to 1000 */ + /* iterate over primes from 2000 to 1000 */ while ((prime = primesieve_prev_prime(&it)) >= 1000) printf("%" PRIu64 "\n", prime); primesieve_free_iterator(&it); + return 0; } diff -Nru primesieve-6.3+ds/examples/c/primesieve_iterator.c primesieve-7.0+ds/examples/c/primesieve_iterator.c --- primesieve-6.3+ds/examples/c/primesieve_iterator.c 2017-11-18 12:38:21.000000000 +0000 +++ primesieve-7.0+ds/examples/c/primesieve_iterator.c 2018-06-08 08:51:41.000000000 +0000 @@ -13,11 +13,19 @@ uint64_t sum = 0; uint64_t prime = 0; - /* iterate over the primes below 10^10 */ - while ((prime = primesieve_next_prime(&it)) < 10000000000ull) + /* iterate over the primes below 10^9 */ + while ((prime = primesieve_next_prime(&it)) < 1000000000ull) sum += prime; + printf("Sum of the primes below 10^9 = %" PRIu64 "\n", sum); + + /* generate primes > 1000 */ + primesieve_skipto(&it, 1000, 1100); + + while ((prime = primesieve_next_prime(&it)) < 1100) + printf("%" PRIu64 "\n", prime); + primesieve_free_iterator(&it); - printf("Sum of the primes below 10^10 = %" PRIu64 "\n", sum); + return 0; } diff -Nru primesieve-6.3+ds/examples/cpp/CMakeLists.txt primesieve-7.0+ds/examples/cpp/CMakeLists.txt --- primesieve-6.3+ds/examples/cpp/CMakeLists.txt 2017-11-18 12:38:21.000000000 +0000 +++ primesieve-7.0+ds/examples/cpp/CMakeLists.txt 2018-06-08 08:51:41.000000000 +0000 @@ -2,5 +2,5 @@ foreach(file ${files}) get_filename_component(binary_name ${file} NAME_WE) add_executable(${binary_name} ${file}) - target_link_libraries(${binary_name} libprimesieve) + target_link_libraries(${binary_name} primesieve::primesieve) endforeach() diff -Nru primesieve-6.3+ds/examples/cpp/nth_prime.cpp primesieve-7.0+ds/examples/cpp/nth_prime.cpp --- primesieve-6.3+ds/examples/cpp/nth_prime.cpp 2017-11-18 12:38:21.000000000 +0000 +++ primesieve-7.0+ds/examples/cpp/nth_prime.cpp 2018-06-08 08:51:41.000000000 +0000 @@ -9,6 +9,7 @@ int main(int, char** argv) { uint64_t n = 1000; + if (argv[1]) n = std::atol(argv[1]); diff -Nru primesieve-6.3+ds/examples/cpp/prev_prime.cpp primesieve-7.0+ds/examples/cpp/prev_prime.cpp --- primesieve-6.3+ds/examples/cpp/prev_prime.cpp 2017-11-18 12:38:21.000000000 +0000 +++ primesieve-7.0+ds/examples/cpp/prev_prime.cpp 2018-06-08 08:51:41.000000000 +0000 @@ -10,7 +10,7 @@ it.skipto(2000); uint64_t prime = it.prev_prime(); - // iterate over the primes from 2000 to 1000 + // iterate over primes from 2000 to 1000 for (; prime >= 1000; prime = it.prev_prime()) std::cout << prime << std::endl; diff -Nru primesieve-6.3+ds/examples/cpp/primesieve_iterator.cpp primesieve-7.0+ds/examples/cpp/primesieve_iterator.cpp --- primesieve-6.3+ds/examples/cpp/primesieve_iterator.cpp 2017-11-18 12:38:21.000000000 +0000 +++ primesieve-7.0+ds/examples/cpp/primesieve_iterator.cpp 2018-06-08 08:51:41.000000000 +0000 @@ -10,10 +10,18 @@ uint64_t prime = it.next_prime(); uint64_t sum = 0; - // iterate over the primes below 10^10 - for (; prime < 10000000000ull; prime = it.next_prime()) + // iterate over the primes below 10^9 + for (; prime < 1000000000ull; prime = it.next_prime()) sum += prime; - std::cout << "Sum of the primes below 10^10 = " << sum << std::endl; + std::cout << "Sum of the primes below 10^9 = " << sum << std::endl; + + // generate primes > 1000 + it.skipto(1000); + prime = it.next_prime(); + + for (; prime < 1100; prime = it.next_prime()) + std::cout << prime << std::endl; + return 0; } diff -Nru primesieve-6.3+ds/examples/cpp/store_primes_in_vector.cpp primesieve-7.0+ds/examples/cpp/store_primes_in_vector.cpp --- primesieve-6.3+ds/examples/cpp/store_primes_in_vector.cpp 2017-11-18 12:38:21.000000000 +0000 +++ primesieve-7.0+ds/examples/cpp/store_primes_in_vector.cpp 2018-06-08 08:51:41.000000000 +0000 @@ -8,13 +8,23 @@ { std::vector primes; - // Store the primes <= 1000 + // Store primes <= 1000 primesieve::generate_primes(1000, &primes); primes.clear(); - // Store the first 1000 primes + // Store primes inside [1000, 2000] + primesieve::generate_primes(1000, 2000, &primes); + + primes.clear(); + + // Store first 1000 primes primesieve::generate_n_primes(1000, &primes); + primes.clear(); + + // Store first 10 primes >= 1000 + primesieve::generate_n_primes(10, 1000, &primes); + return 0; } diff -Nru primesieve-6.3+ds/include/primesieve/Bucket.hpp primesieve-7.0+ds/include/primesieve/Bucket.hpp --- primesieve-6.3+ds/include/primesieve/Bucket.hpp 2017-11-18 12:38:21.000000000 +0000 +++ primesieve-7.0+ds/include/primesieve/Bucket.hpp 2018-06-08 08:51:41.000000000 +0000 @@ -5,7 +5,7 @@ /// once there is no more space in the current Bucket /// a new Bucket is allocated. /// -/// Copyright (C) 2017 Kim Walisch, +/// Copyright (C) 2018 Kim Walisch, /// /// This file is distributed under the BSD License. See the COPYING /// file in the top level directory. @@ -22,10 +22,10 @@ namespace primesieve { /// Each SievingPrime object contains a sieving prime and the -/// position of its next multiple within the SieveOfEratosthenes -/// array i.e. multipleIndex and a wheelIndex. In order to -/// reduce memory usage the multipleIndex and wheelIndex are -/// packed into a single 32-bit variable. +/// position of its next multiple inside the sieve array i.e. +/// multipleIndex and a wheelIndex. In order to reduce the memory +/// usage the multipleIndex and wheelIndex are packed into a +/// single 32-bit variable. /// class SievingPrime { diff -Nru primesieve-6.3+ds/include/primesieve/calculator.hpp primesieve-7.0+ds/include/primesieve/calculator.hpp --- primesieve-6.3+ds/include/primesieve/calculator.hpp 1970-01-01 00:00:00.000000000 +0000 +++ primesieve-7.0+ds/include/primesieve/calculator.hpp 2018-06-08 08:51:41.000000000 +0000 @@ -0,0 +1,463 @@ +/// +/// @file calculator.hpp +/// @brief calculator::eval(const std::string&) evaluates an integer +/// arithmetic expression and returns the result. If an error +/// occurs a calculator::error exception is thrown. +/// +/// @author Kim Walisch, +/// @copyright Copyright (C) 2013-2018 Kim Walisch +/// @license BSD 2-Clause, https://opensource.org/licenses/BSD-2-Clause +/// @version 1.3 patched: `^' is raise to power instead of XOR. +/// +/// == Supported operators == +/// +/// OPERATOR NAME ASSOCIATIVITY PRECEDENCE +/// +/// | Bitwise Inclusive OR Left 4 +/// & Bitwise AND Left 6 +/// << Shift Left Left 9 +/// >> Shift Right Left 9 +/// + Addition Left 10 +/// - Subtraction Left 10 +/// * Multiplication Left 20 +/// / Division Left 20 +/// % Modulo Left 20 +/// ^, ** Raise to power Right 30 +/// e, E Scientific notation Right 40 +/// ~ Unary complement Left 99 +/// +/// The operator precedence has been set according to (uses the C and +/// C++ operator precedence): https://en.wikipedia.org/wiki/Order_of_operations +/// Operators with higher precedence are evaluated before operators +/// with relatively lower precedence. Unary operators are set to have +/// the highest precedence, this is not strictly correct for the power +/// operator e.g. "-3**2" = 9 but a lot of software tools (Bash shell, +/// Microsoft Excel, GNU bc, ...) use the same convention. +/// +/// == Examples of valid expressions == +/// +/// "65536 >> 15" = 2 +/// "2**16" = 65536 +/// "(0 + 0xDf234 - 1000)*3/2%999" = 828 +/// "-(2**2**2**2)" = -65536 +/// "(0 + ~(0xDF234 & 1000) *3) /-2" = 817 +/// "(2**16) + (1 << 16) >> 0X5" = 4096 +/// "5*-(2**(9+7))/3+5*(1 & 0xFf123)" = -109221 +/// +/// == About the algorithm used == +/// +/// calculator::eval(std::string&) relies on the ExpressionParser +/// class which is a simple C++ operator precedence parser with infix +/// notation for integer arithmetic expressions. +/// ExpressionParser has its roots in a JavaScript parser published +/// at: http://stackoverflow.com/questions/28256/equation-expression-parser-with-precedence/114961#114961 +/// The same author has also published an article about his operator +/// precedence algorithm at PerlMonks: +/// http://www.perlmonks.org/?node_id=554516 +/// + +#ifndef CALCULATOR_HPP +#define CALCULATOR_HPP + +#include +#include +#include +#include +#include +#include + +namespace calculator +{ + +/// calculator::eval() throws a calculator::error if it fails +/// to evaluate the expression string. +/// +class error : public std::runtime_error +{ +public: + error(const std::string& expr, const std::string& message) + : std::runtime_error(message), + expr_(expr) + { } +#if __cplusplus >= 201103L || \ + (defined(_MSC_VER) && _MSC_VER >= 1800) + ~error() { } +#else + ~error() throw() { } +#endif + std::string expression() const + { + return expr_; + } +private: + std::string expr_; +}; + +template +class ExpressionParser +{ +public: + /// Evaluate an integer arithmetic expression and return its result. + /// @throw error if parsing fails. + /// + T eval(const std::string& expr) + { + T result = 0; + index_ = 0; + expr_ = expr; + try + { + result = parseExpr(); + if (!isEnd()) + unexpected(); + } + catch (const calculator::error&) + { + while(!stack_.empty()) + stack_.pop(); + throw; + } + return result; + } + + /// Get the integer value of a character. + T eval(char c) + { + std::string expr(1, c); + return eval(expr); + } + +private: + enum + { + OPERATOR_NULL, + OPERATOR_BITWISE_OR, /// | + OPERATOR_BITWISE_XOR, /// ^ + OPERATOR_BITWISE_AND, /// & + OPERATOR_BITWISE_SHL, /// << + OPERATOR_BITWISE_SHR, /// >> + OPERATOR_ADDITION, /// + + OPERATOR_SUBTRACTION, /// - + OPERATOR_MULTIPLICATION, /// * + OPERATOR_DIVISION, /// / + OPERATOR_MODULO, /// % + OPERATOR_POWER, /// ** + OPERATOR_EXPONENT /// e, E + }; + + struct Operator + { + /// Operator, one of the OPERATOR_* enum definitions + int op; + int precedence; + /// 'L' = left or 'R' = right + int associativity; + Operator(int opr, int prec, int assoc) : + op(opr), + precedence(prec), + associativity(assoc) + { } + }; + + struct OperatorValue + { + Operator op; + T value; + OperatorValue(const Operator& opr, T val) : + op(opr), + value(val) + { } + int getPrecedence() const + { + return op.precedence; + } + bool isNull() const + { + return op.op == OPERATOR_NULL; + } + }; + + /// Expression string + std::string expr_; + /// Current expression index, incremented whilst parsing + std::size_t index_; + /// The current operator and its left value + /// are pushed onto the stack if the operator on + /// top of the stack has lower precedence. + std::stack stack_; + + /// Exponentiation by squaring, x^n. + static T pow(T x, T n) + { + T res = 1; + + while (n > 0) + { + if (n % 2 != 0) + { + res *= x; + n -= 1; + } + n /= 2; + + if (n > 0) + x *= x; + } + + return res; + } + + T checkZero(T value) const + { + if (value == 0) + { + std::string divOperators("/%"); + std::size_t division = expr_.find_last_of(divOperators, index_ - 2); + std::ostringstream msg; + msg << "Parser error: division by 0"; + if (division != std::string::npos) + msg << " (error token is \"" + << expr_.substr(division, expr_.size() - division) + << "\")"; + throw calculator::error(expr_, msg.str()); + } + return value; + } + + T calculate(T v1, T v2, const Operator& op) const + { + switch (op.op) + { + case OPERATOR_BITWISE_OR: return v1 | v2; + case OPERATOR_BITWISE_XOR: return v1 ^ v2; + case OPERATOR_BITWISE_AND: return v1 & v2; + case OPERATOR_BITWISE_SHL: return v1 << v2; + case OPERATOR_BITWISE_SHR: return v1 >> v2; + case OPERATOR_ADDITION: return v1 + v2; + case OPERATOR_SUBTRACTION: return v1 - v2; + case OPERATOR_MULTIPLICATION: return v1 * v2; + case OPERATOR_DIVISION: return v1 / checkZero(v2); + case OPERATOR_MODULO: return v1 % checkZero(v2); + case OPERATOR_POWER: return pow(v1, v2); + case OPERATOR_EXPONENT: return v1 * pow(10, v2); + default: return 0; + } + } + + bool isEnd() const + { + return index_ >= expr_.size(); + } + + /// Returns the character at the current expression index or + /// 0 if the end of the expression is reached. + /// + char getCharacter() const + { + if (!isEnd()) + return expr_[index_]; + return 0; + } + + /// Parse str at the current expression index. + /// @throw error if parsing fails. + /// + void expect(const std::string& str) + { + if (expr_.compare(index_, str.size(), str) != 0) + unexpected(); + index_ += str.size(); + } + + void unexpected() const + { + std::ostringstream msg; + msg << "Syntax error: unexpected token \"" + << expr_.substr(index_, expr_.size() - index_) + << "\" at index " + << index_; + throw calculator::error(expr_, msg.str()); + } + + /// Eat all white space characters at the + /// current expression index. + /// + void eatSpaces() + { + while (std::isspace(getCharacter()) != 0) + index_++; + } + + /// Parse a binary operator at the current expression index. + /// @return Operator with precedence and associativity. + /// + Operator parseOp() + { + eatSpaces(); + switch (getCharacter()) + { + case '|': index_++; return Operator(OPERATOR_BITWISE_OR, 4, 'L'); + case '&': index_++; return Operator(OPERATOR_BITWISE_AND, 6, 'L'); + case '<': expect("<<"); return Operator(OPERATOR_BITWISE_SHL, 9, 'L'); + case '>': expect(">>"); return Operator(OPERATOR_BITWISE_SHR, 9, 'L'); + case '+': index_++; return Operator(OPERATOR_ADDITION, 10, 'L'); + case '-': index_++; return Operator(OPERATOR_SUBTRACTION, 10, 'L'); + case '/': index_++; return Operator(OPERATOR_DIVISION, 20, 'L'); + case '%': index_++; return Operator(OPERATOR_MODULO, 20, 'L'); + case '*': index_++; if (getCharacter() != '*') + return Operator(OPERATOR_MULTIPLICATION, 20, 'L'); + index_++; return Operator(OPERATOR_POWER, 30, 'R'); + case '^': index_++; return Operator(OPERATOR_POWER, 30, 'R'); + case 'e': index_++; return Operator(OPERATOR_EXPONENT, 40, 'R'); + case 'E': index_++; return Operator(OPERATOR_EXPONENT, 40, 'R'); + default : return Operator(OPERATOR_NULL, 0, 'L'); + } + } + + static T toInteger(char c) + { + if (c >= '0' && c <= '9') return c -'0'; + if (c >= 'a' && c <= 'f') return c -'a' + 0xa; + if (c >= 'A' && c <= 'F') return c -'A' + 0xa; + T noDigit = 0xf + 1; + return noDigit; + } + + T getInteger() const + { + return toInteger(getCharacter()); + } + + T parseDecimal() + { + T value = 0; + for (T d; (d = getInteger()) <= 9; index_++) + value = value * 10 + d; + return value; + } + + T parseHex() + { + index_ = index_ + 2; + T value = 0; + for (T h; (h = getInteger()) <= 0xf; index_++) + value = value * 0x10 + h; + return value; + } + + bool isHex() const + { + if (index_ + 2 < expr_.size()) + { + char x = expr_[index_ + 1]; + char h = expr_[index_ + 2]; + return (std::tolower(x) == 'x' && toInteger(h) <= 0xf); + } + return false; + } + + /// Parse an integer value at the current expression index. + /// The unary `+', `-' and `~' operators and opening + /// parentheses `(' cause recursion. + /// + T parseValue() + { + T val = 0; + eatSpaces(); + switch (getCharacter()) + { + case '0': if (isHex()) + val = parseHex(); + else + val = parseDecimal(); + break; + case '1': case '2': case '3': case '4': case '5': + case '6': case '7': case '8': case '9': + val = parseDecimal(); + break; + case '(': index_++; + val = parseExpr(); + eatSpaces(); + if (getCharacter() != ')') + { + if (!isEnd()) + unexpected(); + throw calculator::error(expr_, "Syntax error: `)' expected at end of expression"); + } + index_++; break; + case '~': index_++; val = ~parseValue(); break; + case '+': index_++; val = parseValue(); break; + case '-': index_++; val = parseValue() * static_cast(-1); + break; + default : if (!isEnd()) + unexpected(); + throw calculator::error(expr_, "Syntax error: value expected at end of expression"); + } + return val; + } + + /// Parse all operations of the current parenthesis + /// level and the levels above, when done + /// return the result (value). + /// + T parseExpr() + { + stack_.push(OperatorValue(Operator(OPERATOR_NULL, 0, 'L'), 0)); + // first parse value on the left + T value = parseValue(); + + while (!stack_.empty()) + { + // parse an operator (+, -, *, ...) + Operator op(parseOp()); + while (op.precedence < stack_.top().getPrecedence() || ( + op.precedence == stack_.top().getPrecedence() && + op.associativity == 'L')) + { + // end reached + if (stack_.top().isNull()) + { + stack_.pop(); + return value; + } + // do the calculation ("reduce"), producing a new value + value = calculate(stack_.top().value, value, stack_.top().op); + stack_.pop(); + } + + // store on stack_ and continue parsing ("shift") + stack_.push(OperatorValue(op, value)); + // parse value on the right + value = parseValue(); + } + return 0; + } +}; + +template +inline T eval(const std::string& expression) +{ + ExpressionParser parser; + return parser.eval(expression); +} + +template +inline T eval(char c) +{ + ExpressionParser parser; + return parser.eval(c); +} + +inline int eval(const std::string& expression) +{ + return eval(expression); +} + +inline int eval(char c) +{ + return eval(c); +} + +} // namespace calculator + +#endif diff -Nru primesieve-6.3+ds/include/primesieve/config.hpp primesieve-7.0+ds/include/primesieve/config.hpp --- primesieve-6.3+ds/include/primesieve/config.hpp 2017-11-18 12:38:21.000000000 +0000 +++ primesieve-7.0+ds/include/primesieve/config.hpp 2018-06-08 08:51:41.000000000 +0000 @@ -2,36 +2,23 @@ /// @file config.hpp /// @brief primesieve compile time constants. /// -/// Copyright (C) 2017 Kim Walisch, +/// Copyright (C) 2018 Kim Walisch, /// /// This file is distributed under the BSD License. See the COPYING /// file in the top level directory. /// -#ifndef CONFIG_PRIMESIEVE_HPP -#define CONFIG_PRIMESIEVE_HPP +#ifndef CONFIG_HPP +#define CONFIG_HPP #include -/// Disable assert() macro +/// Disable assert() by default #if !defined(DEBUG) && !defined(NDEBUG) #define NDEBUG #endif namespace primesieve { - -/// byte_t must be unsigned in primesieve -typedef unsigned char byte_t; -typedef unsigned int uint_t; - -enum { - /// SieveOfEratosthenes objects use a bit array with 30 numbers per - /// byte for sieving, the 8 bits of each byte correspond to the - /// offsets { 7, 11, 13, 17, 19, 23, 29, 31 }. - /// - NUMBERS_PER_BYTE = 30 -}; - namespace config { enum { diff -Nru primesieve-6.3+ds/include/primesieve/CpuInfo.hpp primesieve-7.0+ds/include/primesieve/CpuInfo.hpp --- primesieve-6.3+ds/include/primesieve/CpuInfo.hpp 2017-11-18 12:38:21.000000000 +0000 +++ primesieve-7.0+ds/include/primesieve/CpuInfo.hpp 2018-06-08 08:51:41.000000000 +0000 @@ -2,7 +2,7 @@ /// @file CpuInfo.hpp /// @brief Get the CPUs' cache sizes in bytes /// -/// Copyright (C) 2017 Kim Walisch, +/// Copyright (C) 2018 Kim Walisch, /// /// This file is distributed under the BSD License. See the COPYING /// file in the top level directory. @@ -32,7 +32,7 @@ std::size_t l2CacheSize_; bool privateL2Cache_; std::string error_; - void initCache(); + void init(); }; // Singleton diff -Nru primesieve-6.3+ds/include/primesieve/EratBig.hpp primesieve-7.0+ds/include/primesieve/EratBig.hpp --- primesieve-6.3+ds/include/primesieve/EratBig.hpp 2017-11-18 12:38:21.000000000 +0000 +++ primesieve-7.0+ds/include/primesieve/EratBig.hpp 2018-06-08 08:51:41.000000000 +0000 @@ -1,7 +1,7 @@ /// /// @file EratBig.hpp /// -/// Copyright (C) 2017 Kim Walisch, +/// Copyright (C) 2018 Kim Walisch, /// /// This file is distributed under the BSD License. See the COPYING /// file in the top level directory. @@ -10,9 +10,9 @@ #ifndef ERATBIG_HPP #define ERATBIG_HPP -#include "config.hpp" #include "Bucket.hpp" #include "Wheel.hpp" +#include "types.hpp" #include #include @@ -27,8 +27,9 @@ class EratBig : public Wheel210_t { public: - EratBig(uint64_t, uint64_t, uint64_t); + void init(uint64_t, uint64_t, uint64_t); void crossOff(byte_t*); + bool enabled() const { return enabled_; } private: uint64_t maxPrime_; uint64_t log2SieveSize_; @@ -39,11 +40,12 @@ Bucket* stock_; /// Pointers of the allocated buckets std::vector> memory_; + bool enabled_ = false; void init(uint64_t); - static void moveBucket(Bucket&, Bucket*&); void pushBucket(uint64_t); void storeSievingPrime(uint64_t, uint64_t, uint64_t); void crossOff(byte_t*, SievingPrime*, SievingPrime*); + static void moveBucket(Bucket&, Bucket*&); }; } // namespace diff -Nru primesieve-6.3+ds/include/primesieve/Erat.hpp primesieve-7.0+ds/include/primesieve/Erat.hpp --- primesieve-6.3+ds/include/primesieve/Erat.hpp 1970-01-01 00:00:00.000000000 +0000 +++ primesieve-7.0+ds/include/primesieve/Erat.hpp 2018-06-08 08:51:41.000000000 +0000 @@ -0,0 +1,111 @@ +/// +/// @file Erat.hpp +/// +/// Copyright (C) 2018 Kim Walisch, +/// +/// This file is distributed under the BSD License. See the COPYING +/// file in the top level directory. +/// + +#ifndef ERAT_HPP +#define ERAT_HPP + +#include "EratSmall.hpp" +#include "EratMedium.hpp" +#include "EratBig.hpp" +#include "types.hpp" + +#include +#include +#include + +namespace primesieve { + +class PreSieve; + +/// The abstract Erat class sieves primes using the segmented sieve +/// of Eratosthenes. It uses a bit array for sieving, the bit array +/// uses 8 flags for 30 numbers. Erat uses 3 different sieve of +/// Eratosthenes algorithms optimized for small, medium and big +/// sieving primes to cross-off multiples. +/// +class Erat +{ +public: + uint64_t getSieveSize() const; + uint64_t getStop() const; +protected: + /// Sieve primes >= start_ + uint64_t start_ = 0; + /// Sieve primes <= stop_ + uint64_t stop_ = 0; + /// Size of sieve_ in bytes (power of 2) + uint64_t sieveSize_ = 0; + /// Lower bound of the current segment + uint64_t segmentLow_ = ~0ull; + /// Upper bound of the current segment + uint64_t segmentHigh_ = 0; + /// Sieve of Eratosthenes array + byte_t* sieve_ = nullptr; + PreSieve* preSieve_; + Erat(); + Erat(uint64_t, uint64_t); + virtual ~Erat(); + void init(uint64_t, uint64_t, uint64_t, PreSieve&); + void addSievingPrime(uint64_t); + void sieveSegment(); + bool hasNextSegment() const; + static uint64_t nextPrime(uint64_t*, uint64_t); +private: + static const std::array bruijnBitValues_; + uint64_t maxPreSieve_; + uint64_t maxEratSmall_; + uint64_t maxEratMedium_; + std::unique_ptr deleter_; + EratSmall eratSmall_; + EratMedium eratMedium_; + EratBig eratBig_; + static uint64_t byteRemainder(uint64_t); + void initSieve(uint64_t); + void initErat(); + void preSieve(); + void crossOff(); + void sieveLastSegment(); +}; + +/// Reconstruct the prime number corresponding to +/// the first set bit and unset that bit +/// +inline uint64_t Erat::nextPrime(uint64_t* bits, uint64_t low) +{ + // calculate bitValues_[bitScanForward(*bits)] + // using a custom De Bruijn bitscan + uint64_t debruijn = 0x3F08A4C6ACB9DBDull; + uint64_t mask = *bits - 1; + uint64_t bitValue = bruijnBitValues_[((*bits ^ mask) * debruijn) >> 58]; + uint64_t prime = low + bitValue; + *bits &= mask; + return prime; +} + +inline void Erat::addSievingPrime(uint64_t prime) +{ + if (prime > maxEratMedium_) eratBig_.addSievingPrime(prime, segmentLow_); + else if (prime > maxEratSmall_) eratMedium_.addSievingPrime(prime, segmentLow_); + else /* (prime > maxPreSieve) */ eratSmall_.addSievingPrime(prime, segmentLow_); +} + +inline uint64_t Erat::getStop() const +{ + return stop_; +} + +/// Sieve size in kilobytes +inline uint64_t Erat::getSieveSize() const +{ + return sieveSize_ / 1024; +} + +} // namespace + +#endif diff -Nru primesieve-6.3+ds/include/primesieve/EratMedium.hpp primesieve-7.0+ds/include/primesieve/EratMedium.hpp --- primesieve-6.3+ds/include/primesieve/EratMedium.hpp 2017-11-18 12:38:21.000000000 +0000 +++ primesieve-7.0+ds/include/primesieve/EratMedium.hpp 2018-06-08 08:51:41.000000000 +0000 @@ -1,7 +1,7 @@ /// /// @file EratMedium.hpp /// -/// Copyright (C) 2017 Kim Walisch, +/// Copyright (C) 2018 Kim Walisch, /// /// This file is distributed under the BSD License. See the COPYING /// file in the top level directory. @@ -10,9 +10,9 @@ #ifndef ERATMEDIUM_HPP #define ERATMEDIUM_HPP -#include "config.hpp" #include "Bucket.hpp" #include "Wheel.hpp" +#include "types.hpp" #include #include @@ -26,11 +26,13 @@ class EratMedium : public Wheel210_t { public: - EratMedium(uint64_t, uint64_t, uint64_t); + void init(uint64_t, uint64_t, uint64_t); void crossOff(byte_t*, uint64_t); + bool enabled() const { return enabled_; } private: uint64_t maxPrime_; std::vector primes_; + bool enabled_ = false; void storeSievingPrime(uint64_t, uint64_t, uint64_t); }; diff -Nru primesieve-6.3+ds/include/primesieve/EratSmall.hpp primesieve-7.0+ds/include/primesieve/EratSmall.hpp --- primesieve-6.3+ds/include/primesieve/EratSmall.hpp 2017-11-18 12:38:21.000000000 +0000 +++ primesieve-7.0+ds/include/primesieve/EratSmall.hpp 2018-06-08 08:51:41.000000000 +0000 @@ -1,7 +1,7 @@ /// /// @file EratSmall.hpp /// -/// Copyright (C) 2017 Kim Walisch, +/// Copyright (C) 2018 Kim Walisch, /// /// This file is distributed under the BSD License. See the COPYING /// file in the top level directory. @@ -10,12 +10,11 @@ #ifndef ERATSMALL_HPP #define ERATSMALL_HPP -#include "config.hpp" #include "Bucket.hpp" #include "Wheel.hpp" +#include "types.hpp" #include -#include #include namespace primesieve { @@ -27,13 +26,15 @@ class EratSmall : public Wheel30_t { public: - EratSmall(uint64_t, uint64_t, uint64_t); static uint64_t getL1Size(uint64_t); + void init(uint64_t, uint64_t, uint64_t); void crossOff(byte_t*, uint64_t); + bool enabled() const { return enabled_; } private: uint64_t maxPrime_; uint64_t l1Size_; std::vector primes_; + bool enabled_ = false; void storeSievingPrime(uint64_t, uint64_t, uint64_t); void crossOff(byte_t*, byte_t*); }; diff -Nru primesieve-6.3+ds/include/primesieve/iterator.h primesieve-7.0+ds/include/primesieve/iterator.h --- primesieve-6.3+ds/include/primesieve/iterator.h 2017-11-18 12:38:21.000000000 +0000 +++ primesieve-7.0+ds/include/primesieve/iterator.h 2018-06-08 08:51:41.000000000 +0000 @@ -5,15 +5,16 @@ * has a complexity of O(r log log r) operations with * r = n^0.5, after that any additional prime is generated in * amortized O(log n log log n) operations. The memory usage - * is about pi(n^0.5) * 16 bytes. + * is about PrimePi(n^0.5) * 8 bytes. * * The @link primesieve_iterator.c primesieve_iterator.c - * @endlink example shows how to use primesieve_iterator. If - * any error occurs errno is set to EDOM and - * primesieve_next_prime() and primesieve_prev_prime() - * return PRIMESIEVE_ERROR. + * @endlink example shows how to use primesieve_iterator. + * If any error occurs primesieve_next_prime() and + * primesieve_prev_prime() return PRIMESIEVE_ERROR. + * Furthermore primesieve_iterator.is_error is initialized + * to 0 and set to 1 if any error occurs. * - * Copyright (C) 2017 Kim Walisch, + * Copyright (C) 2018 Kim Walisch, * * This file is distributed under the BSD License. See the COPYING * file in the top level directory. @@ -35,15 +36,16 @@ */ typedef struct { - size_t i_; - size_t last_idx_; - uint64_t* primes_; - uint64_t* primes_pimpl_; - uint64_t start_; - uint64_t stop_; - uint64_t stop_hint_; - uint64_t tiny_cache_size_; - int is_error_; + size_t i; + size_t last_idx; + uint64_t start; + uint64_t stop; + uint64_t stop_hint; + uint64_t dist; + uint64_t* primes; + void* vector; + void* primeGenerator; + int is_error; } primesieve_iterator; /** Initialize the primesieve iterator before first using it */ @@ -53,7 +55,7 @@ void primesieve_free_iterator(primesieve_iterator* it); /** - * Set the primesieve iterator to start. + * Reset the primesieve iterator to start. * @param start Generate primes > start (or < start). * @param stop_hint Stop number optimization hint. E.g. if you want * to generate the primes below 1000 use @@ -68,23 +70,26 @@ /** Internal use */ void primesieve_generate_prev_primes(primesieve_iterator*); -/** Get the next prime */ +/** + * Get the next prime. + * Returns UINT64_MAX if next prime > 2^64. + */ static inline uint64_t primesieve_next_prime(primesieve_iterator* it) { - if (it->i_++ == it->last_idx_) + if (it->i++ == it->last_idx) primesieve_generate_next_primes(it); - return it->primes_[it->i_]; + return it->primes[it->i]; } /** - * Get the previous prime, - * or 0 if input <= 2 e.g. prev_prime(2) = 0. + * Get the previous prime. + * primesieve_prev_prime(n) = 0 if n <= 2. */ static inline uint64_t primesieve_prev_prime(primesieve_iterator* it) { - if (it->i_-- == 0) + if (it->i-- == 0) primesieve_generate_prev_primes(it); - return it->primes_[it->i_]; + return it->primes[it->i]; } #ifdef __cplusplus diff -Nru primesieve-6.3+ds/include/primesieve/IteratorHelper.hpp primesieve-7.0+ds/include/primesieve/IteratorHelper.hpp --- primesieve-6.3+ds/include/primesieve/IteratorHelper.hpp 1970-01-01 00:00:00.000000000 +0000 +++ primesieve-7.0+ds/include/primesieve/IteratorHelper.hpp 2018-06-08 08:51:41.000000000 +0000 @@ -0,0 +1,33 @@ +/// +/// @file IteratorHelper.hpp +/// +/// Copyright (C) 2018 Kim Walisch, +/// +/// This file is distributed under the BSD License. See the COPYING +/// file in the top level directory. +/// + +#ifndef ITERATOR_HELPER_HPP +#define ITERATOR_HELPER_HPP + +#include + +namespace primesieve { + +class IteratorHelper +{ +public: + static void next(uint64_t* start, + uint64_t* stop, + uint64_t stopHint, + uint64_t* dist); + + static void prev(uint64_t* start, + uint64_t* stop, + uint64_t stopHint, + uint64_t* dist); +}; + +} // namespace + +#endif diff -Nru primesieve-6.3+ds/include/primesieve/iterator.hpp primesieve-7.0+ds/include/primesieve/iterator.hpp --- primesieve-6.3+ds/include/primesieve/iterator.hpp 2017-11-18 12:38:21.000000000 +0000 +++ primesieve-7.0+ds/include/primesieve/iterator.hpp 2018-06-08 08:51:41.000000000 +0000 @@ -1,9 +1,9 @@ /// /// @file iterator.hpp -/// @brief The iterator class allows to easily iterate (forward and -/// backward) over prime numbers. +/// @brief The iterator class allows to easily iterate (forwards +/// and backwards) over prime numbers. /// -/// Copyright (C) 2017 Kim Walisch, +/// Copyright (C) 2018 Kim Walisch, /// /// This file is distributed under the BSD License. See the COPYING /// file in the top level directory. @@ -12,18 +12,22 @@ #ifndef PRIMESIEVE_ITERATOR_HPP #define PRIMESIEVE_ITERATOR_HPP -#include +#include #include +#include +#include namespace primesieve { +class PrimeGenerator; + uint64_t get_max_stop(); /// primesieve::iterator allows to easily iterate over primes both /// forwards and backwards. Generating the first prime has a /// complexity of O(r log log r) operations with r = n^0.5, after that /// any additional prime is generated in amortized O(log n log log n) -/// operations. The memory usage is about pi(n^0.5) * 16 bytes. +/// operations. The memory usage is PrimePi(n^0.5) * 8 bytes. /// class iterator { @@ -37,7 +41,7 @@ /// iterator(uint64_t start = 0, uint64_t stop_hint = get_max_stop()); - /// Reinitialize this iterator object to start. + /// Reset the primesieve iterator to start. /// @param start Generate primes > start (or < start). /// @param stop_hint Stop number optimization hint, gives significant /// speed up if few primes are generated. E.g. if @@ -46,8 +50,8 @@ /// void skipto(uint64_t start, uint64_t stop_hint = get_max_stop()); - /// Advance the iterator by one position. - /// @return The next prime. + /// Get the next prime. + /// Returns UINT64_MAX if next prime > 2^64. /// uint64_t next_prime() { @@ -56,8 +60,8 @@ return primes_[i_]; } - /// Get the previous prime, - /// or 0 if input <= 2 e.g. prev_prime(2) = 0. + /// Get the previous prime. + /// prev_prime(n) = 0 if n <= 2. /// uint64_t prev_prime() { @@ -65,6 +69,8 @@ generate_prev_primes(); return primes_[i_]; } + + ~iterator(); private: std::size_t i_; std::size_t last_idx_; @@ -72,8 +78,8 @@ uint64_t start_; uint64_t stop_; uint64_t stop_hint_; - uint64_t tiny_cache_size_; - uint64_t get_distance(uint64_t); + uint64_t dist_; + std::unique_ptr primeGenerator_; void generate_next_primes(); void generate_prev_primes(); }; diff -Nru primesieve-6.3+ds/include/primesieve/littleendian_cast.hpp primesieve-7.0+ds/include/primesieve/littleendian_cast.hpp --- primesieve-6.3+ds/include/primesieve/littleendian_cast.hpp 2017-11-18 12:38:21.000000000 +0000 +++ primesieve-7.0+ds/include/primesieve/littleendian_cast.hpp 2018-06-08 08:51:41.000000000 +0000 @@ -3,7 +3,7 @@ /// @brief Cast bytes in ascending address order on both little and /// big endian CPUs. /// -/// Copyright (C) 2017 Kim Walisch, +/// Copyright (C) 2018 Kim Walisch, /// /// This file is distributed under the BSD License. See the COPYING /// file in the top level directory. @@ -12,7 +12,7 @@ #ifndef LITTLEENDIAN_CAST_HPP #define LITTLEENDIAN_CAST_HPP -#include "config.hpp" +#include "types.hpp" namespace primesieve { diff -Nru primesieve-6.3+ds/include/primesieve/malloc_vector.hpp primesieve-7.0+ds/include/primesieve/malloc_vector.hpp --- primesieve-6.3+ds/include/primesieve/malloc_vector.hpp 2017-11-18 12:38:21.000000000 +0000 +++ primesieve-7.0+ds/include/primesieve/malloc_vector.hpp 2018-06-08 08:51:41.000000000 +0000 @@ -1,7 +1,7 @@ /// /// @file malloc_vector /// -/// Copyright (C) 2017 Kim Walisch, +/// Copyright (C) 2018 Kim Walisch, /// /// This file is distributed under the BSD License. See the COPYING /// file in the top level directory. @@ -96,7 +96,7 @@ } public: - typedef T value_type; + using value_type = T; private: T* array_; diff -Nru primesieve-6.3+ds/include/primesieve/ParallelPrimeSieve.hpp primesieve-7.0+ds/include/primesieve/ParallelPrimeSieve.hpp --- primesieve-6.3+ds/include/primesieve/ParallelPrimeSieve.hpp 2017-11-18 12:38:21.000000000 +0000 +++ primesieve-7.0+ds/include/primesieve/ParallelPrimeSieve.hpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,57 +0,0 @@ -/// -/// @file ParallelPrimeSieve.hpp -/// @brief The ParallelPrimeSieve class provides an easy API for -/// multi-threaded prime sieving. -/// -/// Copyright (C) 2017 Kim Walisch, -/// -/// This file is distributed under the BSD License. See the COPYING -/// file in the top level directory. -/// - -#ifndef PARALLELPRIMESIEVE_HPP -#define PARALLELPRIMESIEVE_HPP - -#include "PrimeSieve.hpp" -#include -#include - -namespace primesieve { - -class ParallelPrimeSieve : public PrimeSieve -{ -public: - /// Used for inter-process communication with the - /// primesieve GUI application. - struct SharedMemory - { - uint64_t start; - uint64_t stop; - uint64_t counts[6]; - double status; - double seconds; - int flags; - int sieveSize; - int threads; - }; - ParallelPrimeSieve(); - virtual ~ParallelPrimeSieve() { } - void init(SharedMemory&); - static int getMaxThreads(); - int getNumThreads() const; - int idealNumThreads() const; - void setNumThreads(int numThreads); - using PrimeSieve::sieve; - virtual void sieve(); -private: - std::mutex lock_; - SharedMemory* shm_; - int numThreads_; - uint64_t getThreadDistance(int) const; - uint64_t align(uint64_t) const; - virtual bool updateStatus(uint64_t, bool); -}; - -} // namespace - -#endif diff -Nru primesieve-6.3+ds/include/primesieve/ParallelSieve.hpp primesieve-7.0+ds/include/primesieve/ParallelSieve.hpp --- primesieve-6.3+ds/include/primesieve/ParallelSieve.hpp 1970-01-01 00:00:00.000000000 +0000 +++ primesieve-7.0+ds/include/primesieve/ParallelSieve.hpp 2018-06-08 08:51:41.000000000 +0000 @@ -0,0 +1,57 @@ +/// +/// @file ParallelSieve.hpp +/// @brief The ParallelSieve class provides an easy API for +/// multi-threaded prime sieving. +/// +/// Copyright (C) 2018 Kim Walisch, +/// +/// This file is distributed under the BSD License. See the COPYING +/// file in the top level directory. +/// + +#ifndef PARALLELSIEVE_HPP +#define PARALLELSIEVE_HPP + +#include "PrimeSieve.hpp" +#include +#include + +namespace primesieve { + +class ParallelSieve : public PrimeSieve +{ +public: + /// Used for inter-process communication with the + /// primesieve GUI application. + struct SharedMemory + { + uint64_t start; + uint64_t stop; + uint64_t counts[6]; + double status; + double seconds; + int flags; + int sieveSize; + int threads; + }; + ParallelSieve(); + virtual ~ParallelSieve() { } + void init(SharedMemory&); + static int getMaxThreads(); + int getNumThreads() const; + int idealNumThreads() const; + void setNumThreads(int numThreads); + using PrimeSieve::sieve; + virtual void sieve(); +private: + std::mutex lock_; + SharedMemory* shm_; + int numThreads_; + uint64_t getThreadDistance(int) const; + uint64_t align(uint64_t) const; + virtual bool updateStatus(uint64_t, bool); +}; + +} // namespace + +#endif diff -Nru primesieve-6.3+ds/include/primesieve/pmath.hpp primesieve-7.0+ds/include/primesieve/pmath.hpp --- primesieve-6.3+ds/include/primesieve/pmath.hpp 2017-11-18 12:38:21.000000000 +0000 +++ primesieve-7.0+ds/include/primesieve/pmath.hpp 2018-06-08 08:51:41.000000000 +0000 @@ -2,7 +2,7 @@ /// @file pmath.hpp /// @brief Auxiliary math functions for primesieve. /// -/// Copyright (C) 2017 Kim Walisch, +/// Copyright (C) 2018 Kim Walisch, /// /// This file is distributed under the BSD License. See the COPYING /// file in the top level directory. @@ -27,15 +27,17 @@ } template -inline T numberOfBits(T) +inline bool isPow2(T x) { - return (T) (sizeof(T) * 8); + return x != 0 && (x & (x - 1)) == 0; } template -inline bool isPow2(T x) +constexpr T numberOfBits(T) { - return x != 0 && (x & (x - 1)) == 0; + return (T) std::numeric_limits< + typename std::make_unsigned::type + >::digits; } template @@ -43,18 +45,19 @@ { for (T i = 1; i < numberOfBits(x); i += i) x |= (x >> i); + return x - (x >> 1); } template inline T ilog2(T x) { - T bits = numberOfBits(x); - T one = 1; T log2 = 0; + T bits = numberOfBits(x); for (T i = bits / 2; i > 0; i /= 2) { + T one = 1; if (x >= (one << i)) { x >>= i; @@ -65,47 +68,75 @@ return log2; } -/// Integer square root, Newton's method -/// @see book "Hacker's Delight" -/// +#if __cplusplus >= 201402L + +/// C++14 compile time square root using binary search template -inline T isqrt(T x) +constexpr T ctSqrt(T x, T lo, T hi) { - if (x <= 1) - return x; + if (lo == hi) + return lo; - T bits = numberOfBits(x); - T nlz = (bits - 1) - ilog2(x - 1); - T s = bits / 2 - nlz / 2; - T one = 1; + const T mid = (lo + hi + 1) / 2; + + if (x / mid < mid) + return ctSqrt(x, lo, mid - 1); + else + return ctSqrt(x, mid, hi); +} - T g0 = one << s; - T g1 = (g0 + (x >> s)) >> 1; +#else - while (g1 < g0) - { - g0 = g1; - g1 = (g0 + (x / g0)) >> 1; - } +#define MID ((lo + hi + 1) / 2) + +/// C++11 compile time square root using binary search +template +constexpr T ctSqrt(T x, T lo, T hi) +{ + return lo == hi ? lo : ((x / MID < MID) + ? ctSqrt(x, lo, MID - 1) : ctSqrt(x, MID, hi)); +} + +#endif - return g0; +template +constexpr T ctSqrt(T x) +{ + return ctSqrt(x, 0, x / 2 + 1); } -/// Returns 2^64-1 if x + y >= 2^64-1 -inline uint64_t checkedAdd(uint64_t x, uint64_t y) +template +inline T isqrt(T x) { - const uint64_t max = std::numeric_limits::max(); + T r = (T) std::sqrt((double) x); + + constexpr T maxSqrt = ctSqrt(std::numeric_limits::max()); + r = std::min(r, maxSqrt); - if (x >= max - y) - return max; + while (r * r > x) + r--; + while (x - r * r > r * 2) + r++; + + return r; +} - return x + y; +/// Returns 2^64-1 if (x + y) > 2^64-1 +inline uint64_t checkedAdd(uint64_t x, uint64_t y) +{ + if (x >= std::numeric_limits::max() - y) + return std::numeric_limits::max(); + else + return x + y; } -/// Returns 0 if x - y <= 0 +/// Returns 0 if (x - y) < 0 inline uint64_t checkedSub(uint64_t x, uint64_t y) { - return (x > y) ? x - y : 0; + if (x > y) + return x - y; + else + return 0; } template @@ -121,8 +152,8 @@ return x; } -/// prime_count_approx(x) >= pi(x) -inline std::size_t prime_count_approx(uint64_t start, uint64_t stop) +/// primeCountApprox(x) >= pi(x) +inline std::size_t primeCountApprox(uint64_t start, uint64_t stop) { if (start > stop) return 0; @@ -138,19 +169,20 @@ return (std::size_t) pix; } -inline std::size_t prime_count_approx(uint64_t stop) +inline std::size_t primeCountApprox(uint64_t stop) { - return prime_count_approx(0, stop); + return primeCountApprox(0, stop); } /// Approximation of the maximum prime gap near n template -inline T max_prime_gap(T n) +inline T maxPrimeGap(T n) { double x = (double) n; - x = std::max(1.0, x); + x = std::max(8.0, x); double logx = std::log(x); double prime_gap = logx * logx; + return (T) prime_gap; } diff -Nru primesieve-6.3+ds/include/primesieve/PreSieve.hpp primesieve-7.0+ds/include/primesieve/PreSieve.hpp --- primesieve-6.3+ds/include/primesieve/PreSieve.hpp 2017-11-18 12:38:21.000000000 +0000 +++ primesieve-7.0+ds/include/primesieve/PreSieve.hpp 2018-06-08 08:51:41.000000000 +0000 @@ -1,7 +1,7 @@ /// /// @file PreSieve.hpp /// -/// Copyright (C) 2017 Kim Walisch, +/// Copyright (C) 2018 Kim Walisch, /// /// This file is distributed under the BSD License. See the COPYING /// file in the top level directory. @@ -10,7 +10,7 @@ #ifndef PRESIEVE_HPP #define PRESIEVE_HPP -#include "config.hpp" +#include "types.hpp" #include #include @@ -18,11 +18,11 @@ namespace primesieve { /// PreSieve objects are used to pre-sieve multiples of small primes -/// e.g. <= 19 to speed up SieveOfEratosthenes. The idea is to +/// e.g. <= 19 to speed up the sieve of Eratosthenes. The idea is to /// allocate an array (buffer_) and remove the multiples of small /// primes from it at initialization. Then whilst sieving, the -/// buffer_ array is copied to the SieveOfEratosthenes array at the -/// beginning of each new segment to pre-sieve the multiples of small +/// buffer_ array is copied to the sieve array at the beginning of +/// each new segment to pre-sieve the multiples of small /// primes <= maxPrime_. Pre-sieving speeds up my sieve of Eratosthenes /// implementation by about 20 percent when sieving < 10^10. /// @@ -45,9 +45,9 @@ private: uint64_t maxPrime_; uint64_t primeProduct_; + uint64_t size_; byte_t* buffer_; std::unique_ptr deleter_; - uint64_t size_; void init(); }; diff -Nru primesieve-6.3+ds/include/primesieve/PrimeGenerator.hpp primesieve-7.0+ds/include/primesieve/PrimeGenerator.hpp --- primesieve-6.3+ds/include/primesieve/PrimeGenerator.hpp 2017-11-18 12:38:21.000000000 +0000 +++ primesieve-7.0+ds/include/primesieve/PrimeGenerator.hpp 2018-06-08 08:51:41.000000000 +0000 @@ -1,7 +1,12 @@ /// /// @file PrimeGenerator.hpp +/// Generates the primes inside [start, stop] and stores them +/// in a vector. After the primes have been stored in the +/// vector primesieve::iterator iterates over the vector and +/// returns the primes. When there are no more primes left in +/// the vector PrimeGenerator generates new primes. /// -/// Copyright (C) 2017 Kim Walisch, +/// Copyright (C) 2018 Kim Walisch, /// /// This file is distributed under the BSD License. See the COPYING /// file in the top level directory. @@ -10,40 +15,68 @@ #ifndef PRIMEGENERATOR_HPP #define PRIMEGENERATOR_HPP -#include "config.hpp" -#include "SieveOfEratosthenes.hpp" -#include "PrimeSieve.hpp" +#include "Erat.hpp" +#include "PreSieve.hpp" +#include "littleendian_cast.hpp" +#include "SievingPrimes.hpp" #include +#include #include namespace primesieve { -class PreSieve; -class Store; - -/// After a segment has been sieved PrimeGenerator is -/// used to reconstruct primes and prime k-tuplets from -/// 1 bits of the sieve array -/// -class PrimeGenerator : public SieveOfEratosthenes +class PrimeGenerator : public Erat { public: - PrimeGenerator(PrimeSieve&, const PreSieve&); + PrimeGenerator(uint64_t start, uint64_t stop); + void fill(std::vector&); + + bool finished() const + { + return finished_; + } + + static uint64_t maxCachedPrime() + { + return smallPrimes.back(); + } + + void fill(std::vector& primes, + std::size_t* size) + { + if (sieveIdx_ >= sieveSize_) + if (!sieveSegment(primes, size)) + return; + + std::size_t i = 0; + uint64_t bits = littleendian_cast(&sieve_[sieveIdx_]); + sieveIdx_ += 8; + + for (; bits != 0; i++) + primes[i] = nextPrime(&bits, low_); + + *size = i; + low_ += 8 * 30; + } private: - enum { END = 0xff + 1 }; - static const uint64_t bitmasks_[6][5]; - /// Count lookup tables for prime k-tuplets - std::vector kCounts_[6]; - /// Reference to the associated PrimeSieve object - PrimeSieve& ps_; - PrimeSieve::counts_t& counts_; - void init_kCounts(); - virtual void generatePrimes(const byte_t*, uint64_t); - void count(const byte_t*, uint64_t); - void print(const byte_t*, uint64_t) const; - void storePrimes(Store&, const byte_t*, uint64_t) const; - static void printPrime(uint64_t); + uint64_t low_ = 0; + uint64_t sieveIdx_ = ~0ull; + uint64_t prime_ = 0; + PreSieve preSieve_; + SievingPrimes sievingPrimes_; + bool isInit_ = false; + bool finished_ = false; + static const std::array smallPrimes; + static const std::array primePi; + std::size_t getStartIdx() const; + std::size_t getStopIdx() const; + void init(); + void init(std::vector&); + void init(std::vector&, std::size_t*); + bool sieveSegment(std::vector&); + bool sieveSegment(std::vector&, std::size_t*); + void sieveSegment(); }; } // namespace diff -Nru primesieve-6.3+ds/include/primesieve/PrimeSieve.hpp primesieve-7.0+ds/include/primesieve/PrimeSieve.hpp --- primesieve-6.3+ds/include/primesieve/PrimeSieve.hpp 2017-11-18 12:38:21.000000000 +0000 +++ primesieve-7.0+ds/include/primesieve/PrimeSieve.hpp 2018-06-08 08:51:41.000000000 +0000 @@ -1,10 +1,10 @@ /// /// @file PrimeSieve.hpp -/// @brief The PrimeSieve class is a high level class that -/// manages prime sieving using the PreSieve, SievingPrimes -/// and PrimeGenerator classes. +/// @brief PrimeSieve is a high level class that manages prime +/// sieving. It is used for printing and counting primes +/// and for computing the nth prime. /// -/// Copyright (C) 2017 Kim Walisch, +/// Copyright (C) 2018 Kim Walisch, /// /// This file is distributed under the BSD License. See the COPYING /// file in the top level directory. @@ -14,32 +14,33 @@ #define PRIMESIEVE_CLASS_HPP #include -#include +#include namespace primesieve { -class Store; +using counts_t = std::array; + +enum +{ + COUNT_PRIMES = 1 << 0, + COUNT_TWINS = 1 << 1, + COUNT_TRIPLETS = 1 << 2, + COUNT_QUADRUPLETS = 1 << 3, + COUNT_QUINTUPLETS = 1 << 4, + COUNT_SEXTUPLETS = 1 << 5, + PRINT_PRIMES = 1 << 6, + PRINT_TWINS = 1 << 7, + PRINT_TRIPLETS = 1 << 8, + PRINT_QUADRUPLETS = 1 << 9, + PRINT_QUINTUPLETS = 1 << 10, + PRINT_SEXTUPLETS = 1 << 11, + PRINT_STATUS = 1 << 12, + CALCULATE_STATUS = 1 << 13 +}; class PrimeSieve { public: - enum - { - COUNT_PRIMES = 1 << 0, - COUNT_TWINS = 1 << 1, - COUNT_TRIPLETS = 1 << 2, - COUNT_QUADRUPLETS = 1 << 3, - COUNT_QUINTUPLETS = 1 << 4, - COUNT_SEXTUPLETS = 1 << 5, - PRINT_PRIMES = 1 << 6, - PRINT_TWINS = 1 << 7, - PRINT_TRIPLETS = 1 << 8, - PRINT_QUADRUPLETS = 1 << 9, - PRINT_QUINTUPLETS = 1 << 10, - PRINT_SEXTUPLETS = 1 << 11, - PRINT_STATUS = 1 << 12, - CALCULATE_STATUS = 1 << 13 - }; PrimeSieve(); PrimeSieve(PrimeSieve*); virtual ~PrimeSieve(); @@ -49,7 +50,6 @@ int getSieveSize() const; double getStatus() const; double getSeconds() const; - Store& getStore(); // Setters void setStart(uint64_t); void setStop(uint64_t); @@ -57,46 +57,27 @@ void setFlags(int); void addFlags(int); // Bool is* - bool isCount() const; bool isCount(int) const; + bool isCountPrimes() const; + bool isCountkTuplets() const; bool isPrint() const; bool isPrint(int) const; + bool isPrintPrimes() const; + bool isPrintkTuplets() const; bool isFlag(int) const; bool isFlag(int, int) const; bool isStatus() const; - bool isStore() const; // Sieve virtual void sieve(); void sieve(uint64_t, uint64_t); void sieve(uint64_t, uint64_t, int); - void storePrimes(uint64_t, uint64_t, Store*); // nth prime uint64_t nthPrime(uint64_t); uint64_t nthPrime(int64_t, uint64_t); - // Print - void printPrimes(uint64_t, uint64_t); - void printTwins(uint64_t, uint64_t); - void printTriplets(uint64_t, uint64_t); - void printQuadruplets(uint64_t, uint64_t); - void printQuintuplets(uint64_t, uint64_t); - void printSextuplets(uint64_t, uint64_t); // Count - uint64_t countPrimes(uint64_t, uint64_t); - uint64_t countTwins(uint64_t, uint64_t); - uint64_t countTriplets(uint64_t, uint64_t); - uint64_t countQuadruplets(uint64_t, uint64_t); - uint64_t countQuintuplets(uint64_t, uint64_t); - uint64_t countSextuplets(uint64_t, uint64_t); - // Count getters - typedef std::vector counts_t; counts_t& getCounts(); - uint64_t getPrimeCount() const; - uint64_t getTwinCount() const; - uint64_t getTripletCount() const; - uint64_t getQuadrupletCount() const; - uint64_t getQuintupletCount() const; - uint64_t getSextupletCount() const; uint64_t getCount(int) const; + uint64_t countPrimes(uint64_t, uint64_t); virtual bool updateStatus(uint64_t, bool tryLock = true); protected: /// Sieve primes >= start_ @@ -120,11 +101,10 @@ int sieveSize_; /// Setter methods set flags e.g. COUNT_PRIMES int flags_; - /// parent ParallelPrimeSieve object + /// parent ParallelSieve object PrimeSieve* parent_; - Store* store_; static void printStatus(double, double); - bool isParallelPrimeSieve() const; + bool isParallelSieve() const; void processSmallPrimes(); }; diff -Nru primesieve-6.3+ds/include/primesieve/PrintPrimes.hpp primesieve-7.0+ds/include/primesieve/PrintPrimes.hpp --- primesieve-6.3+ds/include/primesieve/PrintPrimes.hpp 1970-01-01 00:00:00.000000000 +0000 +++ primesieve-7.0+ds/include/primesieve/PrintPrimes.hpp 2018-06-08 08:51:41.000000000 +0000 @@ -0,0 +1,54 @@ +/// +/// @file PrintPrimes.hpp +/// +/// Copyright (C) 2018 Kim Walisch, +/// +/// This file is distributed under the BSD License. See the COPYING +/// file in the top level directory. +/// + +#ifndef PRIMEGENERATOR_HPP +#define PRIMEGENERATOR_HPP + +#include "Erat.hpp" +#include "PreSieve.hpp" +#include "PrimeSieve.hpp" +#include "types.hpp" + +#include +#include + +namespace primesieve { + +class Store; + +/// After a segment has been sieved PrintPrimes is +/// used to reconstruct primes and prime k-tuplets from +/// 1 bits of the sieve array +/// +class PrintPrimes : public Erat +{ +public: + PrintPrimes(PrimeSieve&); + void sieve(); +private: + enum { END = 0xff + 1 }; + static const uint64_t bitmasks_[6][5]; + uint64_t low_ = 0; + /// Count lookup tables for prime k-tuplets + std::vector kCounts_[6]; + /// Reference to the associated PrimeSieve object + PreSieve preSieve_; + counts_t& counts_; + PrimeSieve& ps_; + void initCounts(); + void print(); + void countPrimes(); + void countkTuplets(); + void printPrimes() const; + void printkTuplets() const; +}; + +} // namespace + +#endif diff -Nru primesieve-6.3+ds/include/primesieve/SieveOfEratosthenes.hpp primesieve-7.0+ds/include/primesieve/SieveOfEratosthenes.hpp --- primesieve-6.3+ds/include/primesieve/SieveOfEratosthenes.hpp 2017-11-18 12:38:21.000000000 +0000 +++ primesieve-7.0+ds/include/primesieve/SieveOfEratosthenes.hpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,133 +0,0 @@ -/// -/// @file SieveOfEratosthenes.hpp -/// -/// Copyright (C) 2017 Kim Walisch, -/// -/// This file is distributed under the BSD License. See the COPYING -/// file in the top level directory. -/// - -#ifndef SIEVEOFERATOSTHENES_HPP -#define SIEVEOFERATOSTHENES_HPP - -#include "config.hpp" -#include "EratSmall.hpp" -#include "EratMedium.hpp" -#include "EratBig.hpp" -#include "pmath.hpp" - -#include -#include - -namespace primesieve { - -class PreSieve; - -/// The abstract SieveOfEratosthenes class sieves primes using -/// the segmented sieve of Eratosthenes. It uses a bit array -/// for sieving, the bit array uses 8 flags for 30 numbers. -/// SieveOfEratosthenes uses 3 different sieve of Eratosthenes -/// algorithms optimized for small, medium and big sieving primes -/// to cross-off multiples. -/// -class SieveOfEratosthenes -{ -public: - uint64_t getStart() const; - uint64_t getStop() const; - uint64_t getSqrtStop() const; - uint64_t getSieveSize() const; - void addSievingPrime(uint64_t); - void sieve(); -protected: - SieveOfEratosthenes(uint64_t, uint64_t, uint64_t, const PreSieve&); - virtual ~SieveOfEratosthenes() { } - virtual void generatePrimes(const byte_t*, uint64_t) = 0; - static uint64_t nextPrime(uint64_t*, uint64_t); - uint64_t getSegmentLow() const; -private: - static const uint64_t bruijnBitValues_[64]; - /// Lower bound of the current segment - uint64_t segmentLow_; - /// Upper bound of the current segment - uint64_t segmentHigh_; - /// Sieve primes >= start_ - uint64_t start_; - /// Sieve primes <= stop_ - uint64_t stop_; - uint64_t sqrtStop_; - const PreSieve& preSieve_; - uint64_t maxPreSieve_; - uint64_t maxEratSmall_; - uint64_t maxEratMedium_; - /// Size of sieve_ in bytes (power of 2) - uint64_t sieveSize_; - /// Sieve of Eratosthenes array - byte_t* sieve_; - std::unique_ptr deleteSieve_; - std::unique_ptr eratSmall_; - std::unique_ptr eratMedium_; - std::unique_ptr eratBig_; - static uint64_t getByteRemainder(uint64_t); - void allocate(); - void preSieve(); - void crossOffMultiples(); - void sieveSegment(); -}; - -/// Reconstruct the prime number corresponding to -/// the first set bit and unset that bit -/// -inline uint64_t SieveOfEratosthenes::nextPrime(uint64_t* bits, uint64_t low) -{ - // calculate bitValues_[bitScanForward(*bits)] - // using a custom De Bruijn bitscan - uint64_t debruijn64 = 0x3F08A4C6ACB9DBDull; - uint64_t mask = *bits - 1; - uint64_t bitValue = bruijnBitValues_[((*bits ^ mask) * debruijn64) >> 58]; - uint64_t prime = low + bitValue; - *bits &= mask; - return prime; -} - -/// This method is called consecutively for all -/// sieving primes up to sqrt(stop) -/// -inline void SieveOfEratosthenes::addSievingPrime(uint64_t prime) -{ - uint64_t square = prime * prime; - - // This loop is executed once all primes <= sqrt(segmentHigh) - // required to sieve the next segment have been - // added to the erat* objects further down - while (segmentHigh_ < square) - sieveSegment(); - - if (prime > maxEratMedium_) eratBig_->addSievingPrime(prime, segmentLow_); - else if (prime > maxEratSmall_) eratMedium_->addSievingPrime(prime, segmentLow_); - else /* (prime > maxPreSieve) */ eratSmall_->addSievingPrime(prime, segmentLow_); -} - -inline uint64_t SieveOfEratosthenes::getStart() const -{ - return start_; -} - -inline uint64_t SieveOfEratosthenes::getStop() const -{ - return stop_; -} - -inline uint64_t SieveOfEratosthenes::getSegmentLow() const -{ - return segmentLow_; -} - -inline uint64_t SieveOfEratosthenes::getSieveSize() const -{ - return sieveSize_; -} - -} // namespace - -#endif diff -Nru primesieve-6.3+ds/include/primesieve/SievingPrimes.hpp primesieve-7.0+ds/include/primesieve/SievingPrimes.hpp --- primesieve-6.3+ds/include/primesieve/SievingPrimes.hpp 2017-11-18 12:38:21.000000000 +0000 +++ primesieve-7.0+ds/include/primesieve/SievingPrimes.hpp 2018-06-08 08:51:41.000000000 +0000 @@ -1,7 +1,7 @@ /// /// @file SievingPrimes.hpp /// -/// Copyright (C) 2017 Kim Walisch, +/// Copyright (C) 2018 Kim Walisch, /// /// This file is distributed under the BSD License. See the COPYING /// file in the top level directory. @@ -10,25 +10,43 @@ #ifndef SIEVINGPRIMES_HPP #define SIEVINGPRIMES_HPP -#include "config.hpp" -#include "SieveOfEratosthenes.hpp" +#include "Erat.hpp" + +#include +#include namespace primesieve { -class PrimeGenerator; class PreSieve; -class SievingPrimes : public SieveOfEratosthenes +class SievingPrimes : public Erat { public: - SievingPrimes(PrimeGenerator&, const PreSieve&); - void generate(); + SievingPrimes() { } + SievingPrimes(Erat*, PreSieve&); + void init(Erat*, PreSieve&); + uint64_t next(); private: - PrimeGenerator& primeGen_; - void generatePrimes(const byte_t*, uint64_t); - void tinyPrimes(); + uint64_t i_ = 0; + uint64_t size_ = 0; + uint64_t low_ = 0; + uint64_t tinyIdx_; + uint64_t sieveIdx_ = ~0ull; + uint64_t primes_[64]; + std::vector tinySieve_; + void fill(); + void tinySieve(); + bool sieveSegment(); }; +inline uint64_t SievingPrimes::next() +{ + while (i_ >= size_) + fill(); + + return primes_[i_++]; +} + } // namespace #endif diff -Nru primesieve-6.3+ds/include/primesieve/StorePrimes.hpp primesieve-7.0+ds/include/primesieve/StorePrimes.hpp --- primesieve-6.3+ds/include/primesieve/StorePrimes.hpp 2017-11-18 12:38:21.000000000 +0000 +++ primesieve-7.0+ds/include/primesieve/StorePrimes.hpp 2018-06-08 08:51:41.000000000 +0000 @@ -1,11 +1,8 @@ /// /// @file StorePrimes.hpp -/// @brief The StorePrimes and Store_N_Primes classes are used to -/// store primes in std::vector objects. These classes -/// implement a callback function which is called -/// consecutively for all primes in [start, stop]. +/// @brief Store primes in a vector. /// -/// Copyright (C) 2017 Kim Walisch, +/// Copyright (C) 2018 Kim Walisch, /// /// This file is distributed under the BSD License. See the COPYING /// file in the top level directory. @@ -14,102 +11,85 @@ #ifndef STOREPRIMES_HPP #define STOREPRIMES_HPP -#include "PrimeSieve.hpp" +#include "iterator.hpp" #include "primesieve_error.hpp" -#include "pmath.hpp" #include +#include +#include #include -#include +#include namespace primesieve { -uint64_t get_max_stop(); - -class Store +/// primeCountApprox(x) >= pi(x) +inline std::size_t prime_count_approx(uint64_t start, uint64_t stop) { -public: - virtual void operator()(uint64_t prime) = 0; - virtual ~Store() { } -}; + if (start > stop) + return 0; + if (stop <= 10) + return 4; + + // pi(x) <= x / (log(x) - 1.1) + 5, for x >= 4 + double x = (double) stop; + double logx = std::log(x); + double div = logx - 1.1; + double pix = (stop - start) / div + 5; + + return (std::size_t) pix; +} template -class StorePrimes : public Store +inline void store_primes(uint64_t start, + uint64_t stop, + T& primes) { -public: - StorePrimes(T& primes) - : primes_(primes) - { } - - // callback function - void operator()(uint64_t prime) - { - primes_.push_back((typename T::value_type) prime); - } + if (start > 0) + start--; + if (~stop == 0) + stop--; - void storePrimes(uint64_t start, uint64_t stop) + if (start < stop) { - if (start <= stop) - { - std::size_t size = primes_.size() + prime_count_approx(start, stop); - primes_.reserve(size); - PrimeSieve ps; - ps.storePrimes(start, stop, this); - } + using V = typename T::value_type; + std::size_t size = primes.size() + prime_count_approx(start, stop); + primes.reserve(size); + + primesieve::iterator it(start, stop); + uint64_t prime = it.next_prime(); + for (; prime <= stop; prime = it.next_prime()) + primes.push_back((V) prime); } -private: - T& primes_; -}; +} template -class Store_N_Primes : public Store +inline void store_n_primes(uint64_t n, + uint64_t start, + T& primes) { -public: - Store_N_Primes(T& primes) - : primes_(primes) - { } - - // callback function - void operator()(uint64_t prime) - { - primes_.push_back((typename T::value_type) prime); - if (--n_ == 0) - throw stop_store(); - } - - void storePrimes(uint64_t n, uint64_t start) - { - n_ = n; - PrimeSieve ps; - std::size_t size = primes_.size() + (std::size_t) n_; - primes_.reserve(size); - try - { - while (n_ > 0) - { - // choose stop > nth prime - uint64_t logx = 50; - uint64_t dist = n_ * logx + 10000; - uint64_t stop = start + dist; - - // fix integer overflow - if (stop < start) - stop = get_max_stop(); - - ps.storePrimes(start, stop, this); - start = stop + 1; - - if (stop >= get_max_stop()) - throw primesieve_error("cannot generate primes > 2^64"); - } - } - catch (stop_store&) { } - } -private: - class stop_store : public std::exception { }; - T& primes_; - uint64_t n_; -}; + if (n == 0) + return; + if (start > 0) + start--; + + std::size_t size = primes.size() + (std::size_t) n; + primes.reserve(size); + using V = typename T::value_type; + + double x = (double) start; + x = std::max(10.0, x); + uint64_t logx = (uint64_t) std::log(x); + uint64_t dist = n * (logx + 1); + uint64_t stop = start + dist; + + primesieve::iterator it(start, stop); + uint64_t prime = it.next_prime(); + for (; n > 0; n--, prime = it.next_prime()) + primes.push_back((V) prime); + + if (~prime == 0) + throw primesieve_error("cannot generate primes > 2^64"); +} } // namespace diff -Nru primesieve-6.3+ds/include/primesieve/types.hpp primesieve-7.0+ds/include/primesieve/types.hpp --- primesieve-6.3+ds/include/primesieve/types.hpp 1970-01-01 00:00:00.000000000 +0000 +++ primesieve-7.0+ds/include/primesieve/types.hpp 2018-06-08 08:51:41.000000000 +0000 @@ -0,0 +1,30 @@ +/// +/// @file types.hpp +/// @brief Types and forward declarations. +/// +/// Copyright (C) 2018 Kim Walisch, +/// +/// This file is distributed under the BSD License. See the COPYING +/// file in the top level directory. +/// + +#ifndef TYPES_HPP +#define TYPES_HPP + +#include + +namespace primesieve { + +/// byte type must be unsigned and have 8-bits +using byte_t = uint8_t; +using uint_t = unsigned int; + +int get_sieve_size(); + +uint64_t get_max_stop(); + +uint64_t popcount(const uint64_t* array, uint64_t size); + +} // namespace + +#endif diff -Nru primesieve-6.3+ds/include/primesieve/Wheel.hpp primesieve-7.0+ds/include/primesieve/Wheel.hpp --- primesieve-6.3+ds/include/primesieve/Wheel.hpp 2017-11-18 12:38:21.000000000 +0000 +++ primesieve-7.0+ds/include/primesieve/Wheel.hpp 2018-06-08 08:51:41.000000000 +0000 @@ -3,7 +3,7 @@ /// @brief Wheel factorization is used to skip multiles of /// small primes in the sieve of Eratosthenes. /// -/// Copyright (C) 2017 Kim Walisch, +/// Copyright (C) 2018 Kim Walisch, /// /// This file is distributed under the BSD License. See the COPYING /// file in the top level directory. @@ -15,6 +15,7 @@ #include "config.hpp" #include "primesieve_error.hpp" #include "Bucket.hpp" +#include "types.hpp" #include #include @@ -67,7 +68,7 @@ public: /// Add a new sieving prime to the sieving algorithm. /// Calculate the first multiple > segmentLow of prime and the - /// position within the SieveOfEratosthenes array of that multiple + /// position within the sieve array of that multiple /// and its wheel index. When done store the sieving prime. /// void addSievingPrime(uint64_t prime, uint64_t segmentLow) @@ -89,15 +90,15 @@ if (nextMultiple > stop_ - multiple) return; nextMultiple += multiple - segmentLow; - uint64_t multipleIndex = nextMultiple / NUMBERS_PER_BYTE; - uint64_t wheelIndex = wheelOffsets_[prime % NUMBERS_PER_BYTE] + INIT[quotient % MODULO].wheelIndex; + uint64_t multipleIndex = nextMultiple / 30; + uint64_t wheelIndex = wheelOffsets_[prime % 30] + INIT[quotient % MODULO].wheelIndex; storeSievingPrime(prime, multipleIndex, wheelIndex); } protected: - Wheel(uint64_t stop, uint64_t sieveSize) : - stop_(stop) + void init(uint64_t stop, uint64_t sieveSize) { + stop_ = stop; uint64_t maxSieveSize = SievingPrime::MAX_MULTIPLEINDEX + 1; if (sieveSize > maxSieveSize) @@ -145,10 +146,10 @@ }; /// 3rd wheel, skips multiples of 2, 3 and 5 -typedef Wheel<30, 8, wheel30, wheel30Init> Wheel30_t; +using Wheel30_t = Wheel<30, 8, wheel30, wheel30Init>; /// 4th wheel, skips multiples of 2, 3, 5 and 7 -typedef Wheel<210, 48, wheel210, wheel210Init> Wheel210_t; +using Wheel210_t = Wheel<210, 48, wheel210, wheel210Init>; } // namespace diff -Nru primesieve-6.3+ds/include/primesieve.h primesieve-7.0+ds/include/primesieve.h --- primesieve-6.3+ds/include/primesieve.h 2017-11-18 12:38:21.000000000 +0000 +++ primesieve-7.0+ds/include/primesieve.h 2018-06-08 08:51:41.000000000 +0000 @@ -4,7 +4,7 @@ * number generation. In case an error occurs errno is set to * EDOM and PRIMESIEVE_ERROR is returned. * - * Copyright (C) 2017 Kim Walisch, + * Copyright (C) 2018 Kim Walisch, * * This file is distributed under the BSD License. */ @@ -12,9 +12,9 @@ #ifndef PRIMESIEVE_H #define PRIMESIEVE_H -#define PRIMESIEVE_VERSION "6.3" -#define PRIMESIEVE_VERSION_MAJOR 6 -#define PRIMESIEVE_VERSION_MINOR 3 +#define PRIMESIEVE_VERSION "7.0" +#define PRIMESIEVE_VERSION_MAJOR 7 +#define PRIMESIEVE_VERSION_MINOR 0 #include diff -Nru primesieve-6.3+ds/include/primesieve.hpp primesieve-7.0+ds/include/primesieve.hpp --- primesieve-6.3+ds/include/primesieve.hpp 2017-11-18 12:38:21.000000000 +0000 +++ primesieve-7.0+ds/include/primesieve.hpp 2018-06-08 08:51:41.000000000 +0000 @@ -1,11 +1,11 @@ /// /// @file primesieve.hpp -/// @brief primesieve C++ API. primesieve is a library for fast prime -/// number generation, in case an error occurs a +/// @brief primesieve C++ API. primesieve is a library for fast +/// prime number generation, in case an error occurs a /// primesieve::primesieve_error exception (derived form -/// std::runtime_error) will be thrown. +/// std::runtime_error) is thrown. /// -/// Copyright (C) 2017 Kim Walisch, +/// Copyright (C) 2018 Kim Walisch, /// /// This file is distributed under the BSD License. /// @@ -13,13 +13,12 @@ #ifndef PRIMESIEVE_HPP #define PRIMESIEVE_HPP -#define PRIMESIEVE_VERSION "6.3" -#define PRIMESIEVE_VERSION_MAJOR 6 -#define PRIMESIEVE_VERSION_MINOR 3 +#define PRIMESIEVE_VERSION "7.0" +#define PRIMESIEVE_VERSION_MAJOR 7 +#define PRIMESIEVE_VERSION_MINOR 0 -#include -#include #include +#include #include #include @@ -34,10 +33,7 @@ inline void generate_primes(uint64_t stop, std::vector* primes) { if (primes) - { - StorePrimes > sp(*primes); - sp.storePrimes(0, stop); - } + store_primes(0, stop, *primes); } /// Store the primes within the interval [start, stop] @@ -47,10 +43,7 @@ inline void generate_primes(uint64_t start, uint64_t stop, std::vector* primes) { if (primes) - { - StorePrimes > sp(*primes); - sp.storePrimes(start, stop); - } + store_primes(start, stop, *primes); } /// Store the first n primes in the primes vector. @@ -58,10 +51,7 @@ inline void generate_n_primes(uint64_t n, std::vector* primes) { if (primes) - { - Store_N_Primes > sp(*primes); - sp.storePrimes(n, 0); - } + store_n_primes(n, 0, *primes); } /// Store the first n primes >= start in the primes vector. @@ -69,10 +59,7 @@ inline void generate_n_primes(uint64_t n, uint64_t start, std::vector* primes) { if (primes) - { - Store_N_Primes > sp(*primes); - sp.storePrimes(n, start); - } + store_n_primes(n, start, *primes); } /// Find the nth prime. diff -Nru primesieve-6.3+ds/README.md primesieve-7.0+ds/README.md --- primesieve-6.3+ds/README.md 2017-11-18 12:38:21.000000000 +0000 +++ primesieve-7.0+ds/README.md 2018-06-08 08:51:41.000000000 +0000 @@ -5,55 +5,51 @@ [![Github Releases](https://img.shields.io/github/release/kimwalisch/primesieve.svg)](https://github.com/kimwalisch/primesieve/releases) primesieve is a program and C/C++ library that generates primes using a highly optimized -sieve of -Eratosthenes implementation. It counts the primes below 10^10 in -just 0.45 seconds on an Intel Core i7-6700 CPU (4 x 3.4GHz). -primesieve can generate primes and -prime k-tuplets -up to 2^64. - -- **Homepage:** http://primesieve.org -- **Binaries:** http://primesieve.org/downloads -- **API:** http://primesieve.org/api +[sieve of Eratosthenes](https://en.wikipedia.org/wiki/Sieve_of_Eratosthenes) +implementation. It counts the primes below 10^10 in just 0.45 seconds on an +Intel Core i7-6700 CPU (4 x 3.4 GHz). primesieve can generate primes and +[prime k-tuplets](https://en.wikipedia.org/wiki/Prime_k-tuple) up to 2^64. + +* **Homepage:** https://primesieve.org +* **Binaries:** https://primesieve.org/downloads +* **API:** https://primesieve.org/api ![primesieve windows screenshot](https://github.com/kimwalisch/primesieve/blob/gh-pages/screenshots/primesieve_win10.png) ## Algorithm complexity primesieve generates primes using the segmented sieve of Eratosthenes with -[wheel factorization](http://en.wikipedia.org/wiki/Wheel_factorization). +[wheel factorization](https://en.wikipedia.org/wiki/Wheel_factorization). This algorithm has a run time complexity of - + operations and uses - + memory. Furthermore primesieve uses the [bucket sieve](http://sweet.ua.pt/tos/software/prime_sieve.html) algorithm for large sieving primes which reduces the memory usage to - + bytes per thread. ## Installation The primesieve console application can be installed using your operating -system's package manager. The primesieve GUI application can be -downloaded from -[http://primesieve.org/downloads](http://primesieve.org/downloads). +system's package manager. The primesieve GUI application can be downloaded from +[https://primesieve.org/downloads](https://primesieve.org/downloads). ```sh # Debian/Ubuntu -sudo apt-get install primesieve - -# Windows Bash -sudo apt-get install primesieve +sudo apt install primesieve # macOS brew install primesieve + +# Windows using Chocolatey package manager +choco install primesieve ``` ## Usage examples -The primesieve console application can generate primes and prime -k-tuplets. +The primesieve console application can generate primes and prime k-tuplets. ```sh # Count the primes below 1e10 using all CPU cores @@ -72,7 +68,7 @@ ## Build instructions Building primesieve requires a compiler which supports C++11 (or later) -and CMake ≥ 3.1. If your compiler does not yet support C++11 you can fall back +and CMake ≥ 3.4. If your compiler does not yet support C++11 you can fall back to [primesieve-5.7.3](https://github.com/kimwalisch/primesieve/tree/v5.7.3) which is written in C++98. @@ -124,12 +120,11 @@ ``` * [More C++ examples](examples/cpp) -* [Browse primesieve's C++ API online](http://primesieve.org/api/primesieve_8hpp.html) +* [Browse primesieve's C++ API online](https://primesieve.org/api/primesieve_8hpp.html) ## C API -primesieve's functions are exposed as C API via the ```primesieve.h``` -header. +primesieve's functions are exposed as C API via the ```primesieve.h``` header. ```C #include @@ -151,7 +146,7 @@ ``` * [More C examples](examples/c) -* [Browse primesieve's C API online](http://primesieve.org/api/primesieve_8h.html) +* [Browse primesieve's C API online](https://primesieve.org/api/primesieve_8h.html) ## Linking against libprimesieve @@ -162,9 +157,9 @@ cc -O2 primes.c -lprimesieve ``` -If you have built primesieve yourself then the default installation path -is ```/usr/local/lib``` which is not part of ```LD_LIBRARY_PATH``` on many -OSes. Hence you need to export some environment variables: +If you have built primesieve yourself then the default installation path is +```/usr/local/lib``` which is not part of ```LD_LIBRARY_PATH``` on many OSes. +Hence you need to export some environment variables: ```sh export LIBRARY_PATH=/usr/local/lib:$LIBRARY_PATH @@ -179,6 +174,23 @@ cl /O2 /EHsc primes.cpp /I primesieve\include /link primesieve.lib ``` +## CMake support + +Since primesieve-6.4 you can easily link against libprimesieve in your +```CMakeLists.txt```: + +```CMake +find_package(primesieve REQUIRED) +target_link_libraries(your_target primesieve::primesieve) +``` + +To link against the static libprimesieve use: + +```CMake +find_package(primesieve REQUIRED static) +target_link_libraries(your_target primesieve::primesieve) +``` + ## Bindings for other languages primesieve natively supports C and C++ and has bindings available for: @@ -202,7 +214,7 @@ Haskell: - primesieve-haskell + primesieve-haskell diff -Nru primesieve-6.3+ds/scripts/update_version.sh primesieve-7.0+ds/scripts/update_version.sh --- primesieve-6.3+ds/scripts/update_version.sh 2017-11-18 12:38:21.000000000 +0000 +++ primesieve-7.0+ds/scripts/update_version.sh 2018-06-08 08:51:41.000000000 +0000 @@ -43,6 +43,17 @@ mv -f $i.tmp $i done +# Update shared libprimesieve version +for i in $(echo CMakeLists.txt) +do + echo "Update shared libprimesieve version in $i" + old_so_major=$(($old_major + 2)) + new_so_major=$(($new_major + 2)) + new_so_version="$new_so_major.$new_minor.0" + sed "s/$old_so_major\.$old_minor\.0/$new_so_version/g" $i > $i.tmp + mv -f $i.tmp $i +done + # Update version for i in $(echo include/primesieve.hpp \ include/primesieve.h) diff -Nru primesieve-6.3+ds/src/api-c.cpp primesieve-7.0+ds/src/api-c.cpp --- primesieve-6.3+ds/src/api-c.cpp 1970-01-01 00:00:00.000000000 +0000 +++ primesieve-7.0+ds/src/api-c.cpp 2018-06-08 08:51:41.000000000 +0000 @@ -0,0 +1,357 @@ +/// +/// @file api-c.cpp +/// @brief primesieve C API. +/// Contains the implementations of the functions declared +/// in the primesieve.h header file. +/// +/// Copyright (C) 2018 Kim Walisch, +/// +/// This file is distributed under the BSD License. See the COPYING +/// file in the top level directory. +/// + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +using namespace std; +using namespace primesieve; + +namespace { + +template +void* store_primes(uint64_t start, uint64_t stop, size_t* size) +{ + try + { + malloc_vector primes; + store_primes(start, stop, primes); + + if (size) + *size = primes.size(); + + primes.disable_free(); + return primes.data(); + } + catch (exception&) + { + errno = EDOM; + if (size) + *size = 0; + } + + return NULL; +} + +template +void* store_n_primes(uint64_t n, uint64_t start) +{ + try + { + malloc_vector primes; + store_n_primes(n, start, primes); + primes.disable_free(); + return primes.data(); + } + catch (exception&) + { + errno = EDOM; + } + + return NULL; +} + +} // namespace + +void* primesieve_generate_primes(uint64_t start, uint64_t stop, size_t* size, int type) +{ + switch (type) + { + case SHORT_PRIMES: return store_primes(start, stop, size); + case USHORT_PRIMES: return store_primes(start, stop, size); + case INT_PRIMES: return store_primes(start, stop, size); + case UINT_PRIMES: return store_primes(start, stop, size); + case LONG_PRIMES: return store_primes(start, stop, size); + case ULONG_PRIMES: return store_primes(start, stop, size); + case LONGLONG_PRIMES: return store_primes(start, stop, size); + case ULONGLONG_PRIMES: return store_primes(start, stop, size); + case INT16_PRIMES: return store_primes(start, stop, size); + case UINT16_PRIMES: return store_primes(start, stop, size); + case INT32_PRIMES: return store_primes(start, stop, size); + case UINT32_PRIMES: return store_primes(start, stop, size); + case INT64_PRIMES: return store_primes(start, stop, size); + case UINT64_PRIMES: return store_primes(start, stop, size); + } + errno = EDOM; + if (size) + *size = 0; + return NULL; +} + +void* primesieve_generate_n_primes(uint64_t n, uint64_t start, int type) +{ + switch (type) + { + case SHORT_PRIMES: return store_n_primes(n, start); + case USHORT_PRIMES: return store_n_primes(n, start); + case INT_PRIMES: return store_n_primes(n, start); + case UINT_PRIMES: return store_n_primes(n, start); + case LONG_PRIMES: return store_n_primes(n, start); + case ULONG_PRIMES: return store_n_primes(n, start); + case LONGLONG_PRIMES: return store_n_primes(n, start); + case ULONGLONG_PRIMES: return store_n_primes(n, start); + case INT16_PRIMES: return store_n_primes(n, start); + case UINT16_PRIMES: return store_n_primes(n, start); + case INT32_PRIMES: return store_n_primes(n, start); + case UINT32_PRIMES: return store_n_primes(n, start); + case INT64_PRIMES: return store_n_primes(n, start); + case UINT64_PRIMES: return store_n_primes(n, start); + } + errno = EDOM; + return NULL; +} + +void primesieve_free(void* primes) +{ + free(primes); +} + +uint64_t primesieve_nth_prime(int64_t n, uint64_t start) +{ + try + { + ParallelSieve ps; + ps.setSieveSize(get_sieve_size()); + ps.setNumThreads(get_num_threads()); + return ps.nthPrime(n, start); + } + catch (exception&) + { + errno = EDOM; + } + return PRIMESIEVE_ERROR; +} + +uint64_t primesieve_count_primes(uint64_t start, uint64_t stop) +{ + try + { + ParallelSieve ps; + ps.setSieveSize(get_sieve_size()); + ps.setNumThreads(get_num_threads()); + ps.sieve(start, stop, COUNT_PRIMES); + return ps.getCount(0); + } + catch (exception&) + { + errno = EDOM; + } + return PRIMESIEVE_ERROR; +} + +uint64_t primesieve_count_twins(uint64_t start, uint64_t stop) +{ + try + { + ParallelSieve ps; + ps.setSieveSize(get_sieve_size()); + ps.setNumThreads(get_num_threads()); + ps.sieve(start, stop, COUNT_TWINS); + return ps.getCount(1); + } + catch (exception&) + { + errno = EDOM; + } + return PRIMESIEVE_ERROR; +} + +uint64_t primesieve_count_triplets(uint64_t start, uint64_t stop) +{ + try + { + ParallelSieve ps; + ps.setSieveSize(get_sieve_size()); + ps.setNumThreads(get_num_threads()); + ps.sieve(start, stop, COUNT_TRIPLETS); + return ps.getCount(2); + } + catch (exception&) + { + errno = EDOM; + } + return PRIMESIEVE_ERROR; +} + +uint64_t primesieve_count_quadruplets(uint64_t start, uint64_t stop) +{ + try + { + ParallelSieve ps; + ps.setSieveSize(get_sieve_size()); + ps.setNumThreads(get_num_threads()); + ps.sieve(start, stop, COUNT_QUADRUPLETS); + return ps.getCount(3); + } + catch (exception&) + { + errno = EDOM; + } + return PRIMESIEVE_ERROR; +} + +uint64_t primesieve_count_quintuplets(uint64_t start, uint64_t stop) +{ + try + { + ParallelSieve ps; + ps.setSieveSize(get_sieve_size()); + ps.setNumThreads(get_num_threads()); + ps.sieve(start, stop, COUNT_QUINTUPLETS); + return ps.getCount(4); + } + catch (exception&) + { + errno = EDOM; + } + return PRIMESIEVE_ERROR; +} + +uint64_t primesieve_count_sextuplets(uint64_t start, uint64_t stop) +{ + try + { + ParallelSieve ps; + ps.setSieveSize(get_sieve_size()); + ps.setNumThreads(get_num_threads()); + ps.sieve(start, stop, COUNT_SEXTUPLETS); + return ps.getCount(5); + } + catch (exception&) + { + errno = EDOM; + } + return PRIMESIEVE_ERROR; +} + +void primesieve_print_primes(uint64_t start, uint64_t stop) +{ + try + { + PrimeSieve ps; + ps.setSieveSize(get_sieve_size()); + ps.sieve(start, stop, PRINT_PRIMES); + } + catch (exception&) + { + errno = EDOM; + } +} + +void primesieve_print_twins(uint64_t start, uint64_t stop) +{ + try + { + PrimeSieve ps; + ps.setSieveSize(get_sieve_size()); + ps.sieve(start, stop, PRINT_TWINS); + } + catch (exception&) + { + errno = EDOM; + } +} + +void primesieve_print_triplets(uint64_t start, uint64_t stop) +{ + try + { + PrimeSieve ps; + ps.setSieveSize(get_sieve_size()); + ps.sieve(start, stop, PRINT_TRIPLETS); + } + catch (exception&) + { + errno = EDOM; + } +} + +void primesieve_print_quadruplets(uint64_t start, uint64_t stop) +{ + try + { + PrimeSieve ps; + ps.setSieveSize(get_sieve_size()); + ps.sieve(start, stop, PRINT_QUADRUPLETS); + } + catch (exception&) + { + errno = EDOM; + } +} + +void primesieve_print_quintuplets(uint64_t start, uint64_t stop) +{ + try + { + PrimeSieve ps; + ps.setSieveSize(get_sieve_size()); + ps.sieve(start, stop, PRINT_QUINTUPLETS); + } + catch (exception&) + { + errno = EDOM; + } +} + +void primesieve_print_sextuplets(uint64_t start, uint64_t stop) +{ + try + { + PrimeSieve ps; + ps.setSieveSize(get_sieve_size()); + ps.sieve(start, stop, PRINT_SEXTUPLETS); + } + catch (exception&) + { + errno = EDOM; + } +} + +int primesieve_get_sieve_size() +{ + return get_sieve_size(); +} + +int primesieve_get_num_threads() +{ + return get_num_threads(); +} + +void primesieve_set_sieve_size(int sieve_size) +{ + set_sieve_size(sieve_size); +} + +void primesieve_set_num_threads(int num_threads) +{ + set_num_threads(num_threads); +} + +uint64_t primesieve_get_max_stop() +{ + return get_max_stop(); +} + +const char* primesieve_version() +{ + return PRIMESIEVE_VERSION; +} diff -Nru primesieve-6.3+ds/src/api.cpp primesieve-7.0+ds/src/api.cpp --- primesieve-6.3+ds/src/api.cpp 1970-01-01 00:00:00.000000000 +0000 +++ primesieve-7.0+ds/src/api.cpp 2018-06-08 08:51:41.000000000 +0000 @@ -0,0 +1,204 @@ +/// +/// @file api.cpp +/// @brief primesieve C++ API. +/// Contains the implementations of the functions declared +/// in the primesieve.hpp header file. +/// +/// Copyright (C) 2018 Kim Walisch, +/// +/// This file is distributed under the BSD License. See the COPYING +/// file in the top level directory. +/// + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +namespace { + +int sieve_size = 0; + +int num_threads = 0; + +} + +namespace primesieve { + +uint64_t nth_prime(int64_t n, uint64_t start) +{ + ParallelSieve ps; + ps.setSieveSize(get_sieve_size()); + ps.setNumThreads(get_num_threads()); + return ps.nthPrime(n, start); +} + +uint64_t count_primes(uint64_t start, uint64_t stop) +{ + ParallelSieve ps; + ps.setSieveSize(get_sieve_size()); + ps.setNumThreads(get_num_threads()); + ps.sieve(start, stop, COUNT_PRIMES); + return ps.getCount(0); +} + +uint64_t count_twins(uint64_t start, uint64_t stop) +{ + ParallelSieve ps; + ps.setSieveSize(get_sieve_size()); + ps.setNumThreads(get_num_threads()); + ps.sieve(start, stop, COUNT_TWINS); + return ps.getCount(1); +} + +uint64_t count_triplets(uint64_t start, uint64_t stop) +{ + ParallelSieve ps; + ps.setSieveSize(get_sieve_size()); + ps.setNumThreads(get_num_threads()); + ps.sieve(start, stop, COUNT_TRIPLETS); + return ps.getCount(2); +} + +uint64_t count_quadruplets(uint64_t start, uint64_t stop) +{ + ParallelSieve ps; + ps.setSieveSize(get_sieve_size()); + ps.setNumThreads(get_num_threads()); + ps.sieve(start, stop, COUNT_QUADRUPLETS); + return ps.getCount(3); +} + +uint64_t count_quintuplets(uint64_t start, uint64_t stop) +{ + ParallelSieve ps; + ps.setSieveSize(get_sieve_size()); + ps.setNumThreads(get_num_threads()); + ps.sieve(start, stop, COUNT_QUINTUPLETS); + return ps.getCount(4); +} + +uint64_t count_sextuplets(uint64_t start, uint64_t stop) +{ + ParallelSieve ps; + ps.setSieveSize(get_sieve_size()); + ps.setNumThreads(get_num_threads()); + ps.sieve(start, stop, COUNT_SEXTUPLETS); + return ps.getCount(5); +} + +void print_primes(uint64_t start, uint64_t stop) +{ + PrimeSieve ps; + ps.setSieveSize(get_sieve_size()); + ps.sieve(start, stop, PRINT_PRIMES); +} + +void print_twins(uint64_t start, uint64_t stop) +{ + PrimeSieve ps; + ps.setSieveSize(get_sieve_size()); + ps.sieve(start, stop, PRINT_TWINS); +} + +void print_triplets(uint64_t start, uint64_t stop) +{ + PrimeSieve ps; + ps.setSieveSize(get_sieve_size()); + ps.sieve(start, stop, PRINT_TRIPLETS); +} + +void print_quadruplets(uint64_t start, uint64_t stop) +{ + PrimeSieve ps; + ps.setSieveSize(get_sieve_size()); + ps.sieve(start, stop, PRINT_QUADRUPLETS); +} + +void print_quintuplets(uint64_t start, uint64_t stop) +{ + PrimeSieve ps; + ps.setSieveSize(get_sieve_size()); + ps.sieve(start, stop, PRINT_QUINTUPLETS); +} + +void print_sextuplets(uint64_t start, uint64_t stop) +{ + PrimeSieve ps; + ps.setSieveSize(get_sieve_size()); + ps.sieve(start, stop, PRINT_SEXTUPLETS); +} + +int get_num_threads() +{ + if (num_threads) + return num_threads; + else + return ParallelSieve::getMaxThreads(); +} + +void set_num_threads(int threads) +{ + num_threads = inBetween(1, threads, ParallelSieve::getMaxThreads()); +} + +uint64_t get_max_stop() +{ + return std::numeric_limits::max(); +} + +std::string primesieve_version() +{ + return PRIMESIEVE_VERSION; +} + +void set_sieve_size(int kilobytes) +{ + sieve_size = inBetween(8, kilobytes, 4096); + sieve_size = floorPow2(sieve_size); +} + +int get_sieve_size() +{ + // user specified sieve size + if (sieve_size) + return sieve_size; + + size_t l1CacheSize = cpuInfo.l1CacheSize(); + size_t l2CacheSize = cpuInfo.l2CacheSize(); + + // convert to kilobytes + l1CacheSize /= 1024; + l2CacheSize /= 1024; + + // check if each CPU core has a private L2 cache + if (cpuInfo.hasL2Cache() && + cpuInfo.privateL2Cache() && + l2CacheSize > l1CacheSize) + { + l2CacheSize = inBetween(32, l2CacheSize, 4096); + l2CacheSize = floorPow2(l2CacheSize); + return (int) l2CacheSize; + } + else + { + if (!cpuInfo.hasL1Cache()) + l1CacheSize = 32; + + // if the CPU does not have an L2 cache or if the + // cache is shared between all CPU cores we + // set the sieve size to the CPU's L1 cache size + + l1CacheSize = inBetween(8, l1CacheSize, 4096); + l1CacheSize = floorPow2(l1CacheSize); + return (int) l1CacheSize; + } +} + +} // namespace diff -Nru primesieve-6.3+ds/src/console/calculator.hpp primesieve-7.0+ds/src/console/calculator.hpp --- primesieve-6.3+ds/src/console/calculator.hpp 2017-11-18 12:38:21.000000000 +0000 +++ primesieve-7.0+ds/src/console/calculator.hpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,458 +0,0 @@ -/// -/// @file calculator.hpp -/// @brief calculator::eval(const std::string&) evaluates an integer -/// arithmetic expression and returns the result. If an error -/// occurs a calculator::error exception is thrown. -/// -/// @author Kim Walisch, -/// @copyright Copyright (C) 2017 Kim Walisch -/// @license BSD 2-Clause, http://opensource.org/licenses/BSD-2-Clause -/// @version 1.1 patched: `^' is raise to power instead of XOR. -/// -/// == Supported operators == -/// -/// OPERATOR NAME ASSOCIATIVITY PRECEDENCE -/// -/// | Bitwise Inclusive OR Left 4 -/// & Bitwise AND Left 6 -/// << Shift Left Left 9 -/// >> Shift Right Left 9 -/// + Addition Left 10 -/// - Subtraction Left 10 -/// * Multiplication Left 20 -/// / Division Left 20 -/// % Modulo Left 20 -/// ^, ** Raise to power Right 30 -/// e, E Scientific notation Right 40 -/// ~ Unary complement Left 99 -/// -/// The operator precedence has been set according to (uses the C and -/// C++ operator precedence): http://en.wikipedia.org/wiki/Order_of_operations -/// Operators with higher precedence are evaluated before operators -/// with relatively lower precedence. Unary operators are set to have -/// the highest precedence, this is not strictly correct for the power -/// operator e.g. "-3**2" = 9 but a lot of software tools (Bash shell, -/// Microsoft Excel, GNU bc, ...) use the same convention. -/// -/// == Examples of valid expressions == -/// -/// "65536 >> 15" = 2 -/// "2**16" = 65536 -/// "(0 + 0xDf234 - 1000)*3/2%999" = 828 -/// "-(2**2**2**2)" = -65536 -/// "(0 + ~(0xDF234 & 1000) *3) /-2" = 817 -/// "(2**16) + (1 << 16) >> 0X5" = 4096 -/// "5*-(2**(9+7))/3+5*(1 & 0xFf123)" = -109221 -/// -/// == About the algorithm used == -/// -/// calculator::eval(std::string&) relies on the ExpressionParser -/// class which is a simple C++ operator precedence parser with infix -/// notation for integer arithmetic expressions. -/// ExpressionParser has its roots in a JavaScript parser published -/// at: http://stackoverflow.com/questions/28256/equation-expression-parser-with-precedence/114961#114961 -/// The same author has also published an article about his operator -/// precedence algorithm at PerlMonks: -/// http://www.perlmonks.org/?node_id=554516 -/// - -#ifndef CALCULATOR_HPP -#define CALCULATOR_HPP - -#include -#include -#include -#include -#include -#include - -namespace calculator -{ - -/// calculator::eval() throws a calculator::error if it fails -/// to evaluate the expression string. -/// -class error : public std::runtime_error -{ -public: - error(const std::string& expr, const std::string& message) - : std::runtime_error(message), - expr_(expr) - { } -#if __cplusplus >= 201103L - ~error() { } -#else - ~error() throw() { } -#endif - std::string expression() const - { - return expr_; - } -private: - std::string expr_; -}; - -template -class ExpressionParser -{ -public: - /// Evaluate an integer arithmetic expression and return its result. - /// @throw error if parsing fails. - /// - T eval(const std::string& expr) - { - T result = 0; - index_ = 0; - expr_ = expr; - try - { - result = parseExpr(); - if (!isEnd()) - unexpected(); - } - catch (const calculator::error&) - { - while(!stack_.empty()) - stack_.pop(); - throw; - } - return result; - } - - /// Get the integer value of a character. - T eval(char c) - { - std::string expr(1, c); - return eval(expr); - } - -private: - enum - { - OPERATOR_NULL, - OPERATOR_BITWISE_OR, /// | - OPERATOR_BITWISE_XOR, /// ^ - OPERATOR_BITWISE_AND, /// & - OPERATOR_BITWISE_SHL, /// << - OPERATOR_BITWISE_SHR, /// >> - OPERATOR_ADDITION, /// + - OPERATOR_SUBTRACTION, /// - - OPERATOR_MULTIPLICATION, /// * - OPERATOR_DIVISION, /// / - OPERATOR_MODULO, /// % - OPERATOR_POWER, /// ** - OPERATOR_EXPONENT /// e, E - }; - - struct Operator - { - /// Operator, one of the OPERATOR_* enum definitions - int op; - int precedence; - /// 'L' = left or 'R' = right - int associativity; - Operator(int opr, int prec, int assoc) : - op(opr), - precedence(prec), - associativity(assoc) - { } - }; - - struct OperatorValue - { - Operator op; - T value; - OperatorValue(const Operator& opr, T val) : - op(opr), - value(val) - { } - int getPrecedence() const - { - return op.precedence; - } - bool isNull() const - { - return op.op == OPERATOR_NULL; - } - }; - - /// Expression string - std::string expr_; - /// Current expression index, incremented whilst parsing - std::size_t index_; - /// The current operator and its left value - /// are pushed onto the stack if the operator on - /// top of the stack has lower precedence. - std::stack stack_; - - /// Exponentiation by squaring, x^n. - static T pow(T x, T n) - { - T res = 1; - while (n != 0) - { - if (n % 2 != 0) - { - res *= x; - n -= 1; - } - x *= x; - n /= 2; - } - return res; - } - - T checkZero(T value) const - { - if (value == 0) - { - std::string divOperators("/%"); - std::size_t division = expr_.find_last_of(divOperators, index_ - 2); - std::ostringstream msg; - msg << "Parser error: division by 0"; - if (division != std::string::npos) - msg << " (error token is \"" - << expr_.substr(division, expr_.size() - division) - << "\")"; - throw calculator::error(expr_, msg.str()); - } - return value; - } - - T calculate(T v1, T v2, const Operator& op) const - { - switch (op.op) - { - case OPERATOR_BITWISE_OR: return v1 | v2; - case OPERATOR_BITWISE_XOR: return v1 ^ v2; - case OPERATOR_BITWISE_AND: return v1 & v2; - case OPERATOR_BITWISE_SHL: return v1 << v2; - case OPERATOR_BITWISE_SHR: return v1 >> v2; - case OPERATOR_ADDITION: return v1 + v2; - case OPERATOR_SUBTRACTION: return v1 - v2; - case OPERATOR_MULTIPLICATION: return v1 * v2; - case OPERATOR_DIVISION: return v1 / checkZero(v2); - case OPERATOR_MODULO: return v1 % checkZero(v2); - case OPERATOR_POWER: return pow(v1, v2); - case OPERATOR_EXPONENT: return v1 * pow(10, v2); - default: return 0; - } - } - - bool isEnd() const - { - return index_ >= expr_.size(); - } - - /// Returns the character at the current expression index or - /// 0 if the end of the expression is reached. - /// - char getCharacter() const - { - if (!isEnd()) - return expr_[index_]; - return 0; - } - - /// Parse str at the current expression index. - /// @throw error if parsing fails. - /// - void expect(const std::string& str) - { - if (expr_.compare(index_, str.size(), str) != 0) - unexpected(); - index_ += str.size(); - } - - void unexpected() const - { - std::ostringstream msg; - msg << "Syntax error: unexpected token \"" - << expr_.substr(index_, expr_.size() - index_) - << "\" at index " - << index_; - throw calculator::error(expr_, msg.str()); - } - - /// Eat all white space characters at the - /// current expression index. - /// - void eatSpaces() - { - while (std::isspace(getCharacter()) != 0) - index_++; - } - - /// Parse a binary operator at the current expression index. - /// @return Operator with precedence and associativity. - /// - Operator parseOp() - { - eatSpaces(); - switch (getCharacter()) - { - case '|': index_++; return Operator(OPERATOR_BITWISE_OR, 4, 'L'); - case '&': index_++; return Operator(OPERATOR_BITWISE_AND, 6, 'L'); - case '<': expect("<<"); return Operator(OPERATOR_BITWISE_SHL, 9, 'L'); - case '>': expect(">>"); return Operator(OPERATOR_BITWISE_SHR, 9, 'L'); - case '+': index_++; return Operator(OPERATOR_ADDITION, 10, 'L'); - case '-': index_++; return Operator(OPERATOR_SUBTRACTION, 10, 'L'); - case '/': index_++; return Operator(OPERATOR_DIVISION, 20, 'L'); - case '%': index_++; return Operator(OPERATOR_MODULO, 20, 'L'); - case '*': index_++; if (getCharacter() != '*') - return Operator(OPERATOR_MULTIPLICATION, 20, 'L'); - index_++; return Operator(OPERATOR_POWER, 30, 'R'); - case '^': index_++; return Operator(OPERATOR_POWER, 30, 'R'); - case 'e': index_++; return Operator(OPERATOR_EXPONENT, 40, 'R'); - case 'E': index_++; return Operator(OPERATOR_EXPONENT, 40, 'R'); - default : return Operator(OPERATOR_NULL, 0, 'L'); - } - } - - static T toInteger(char c) - { - if (c >= '0' && c <= '9') return c -'0'; - if (c >= 'a' && c <= 'f') return c -'a' + 0xa; - if (c >= 'A' && c <= 'F') return c -'A' + 0xa; - T noDigit = 0xf + 1; - return noDigit; - } - - T getInteger() const - { - return toInteger(getCharacter()); - } - - T parseDecimal() - { - T value = 0; - for (T d; (d = getInteger()) <= 9; index_++) - value = value * 10 + d; - return value; - } - - T parseHex() - { - index_ = index_ + 2; - T value = 0; - for (T h; (h = getInteger()) <= 0xf; index_++) - value = value * 0x10 + h; - return value; - } - - bool isHex() const - { - if (index_ + 2 < expr_.size()) - { - char x = expr_[index_ + 1]; - char h = expr_[index_ + 2]; - return (std::tolower(x) == 'x' && toInteger(h) <= 0xf); - } - return false; - } - - /// Parse an integer value at the current expression index. - /// The unary `+', `-' and `~' operators and opening - /// parentheses `(' cause recursion. - /// - T parseValue() - { - T val = 0; - eatSpaces(); - switch (getCharacter()) - { - case '0': if (isHex()) - val = parseHex(); - else - val = parseDecimal(); - break; - case '1': case '2': case '3': case '4': case '5': - case '6': case '7': case '8': case '9': - val = parseDecimal(); - break; - case '(': index_++; - val = parseExpr(); - eatSpaces(); - if (getCharacter() != ')') - { - if (!isEnd()) - unexpected(); - throw calculator::error(expr_, "Syntax error: `)' expected at end of expression"); - } - index_++; break; - case '~': index_++; val = ~parseValue(); break; - case '+': index_++; val = parseValue(); break; - case '-': index_++; val = parseValue() * static_cast(-1); - break; - default : if (!isEnd()) - unexpected(); - throw calculator::error(expr_, "Syntax error: value expected at end of expression"); - } - return val; - } - - /// Parse all operations of the current parenthesis - /// level and the levels above, when done - /// return the result (value). - /// - T parseExpr() - { - stack_.push(OperatorValue(Operator(OPERATOR_NULL, 0, 'L'), 0)); - // first parse value on the left - T value = parseValue(); - - while (!stack_.empty()) - { - // parse an operator (+, -, *, ...) - Operator op(parseOp()); - while (op.precedence < stack_.top().getPrecedence() || ( - op.precedence == stack_.top().getPrecedence() && - op.associativity == 'L')) - { - // end reached - if (stack_.top().isNull()) - { - stack_.pop(); - return value; - } - // do the calculation ("reduce"), producing a new value - value = calculate(stack_.top().value, value, stack_.top().op); - stack_.pop(); - } - - // store on stack_ and continue parsing ("shift") - stack_.push(OperatorValue(op, value)); - // parse value on the right - value = parseValue(); - } - return 0; - } -}; - -template -inline T eval(const std::string& expression) -{ - ExpressionParser parser; - return parser.eval(expression); -} - -template -inline T eval(char c) -{ - ExpressionParser parser; - return parser.eval(c); -} - -inline int eval(const std::string& expression) -{ - return eval(expression); -} - -inline int eval(char c) -{ - return eval(c); -} - -} // namespace calculator - -#endif diff -Nru primesieve-6.3+ds/src/console/cmdoptions.cpp primesieve-7.0+ds/src/console/cmdoptions.cpp --- primesieve-6.3+ds/src/console/cmdoptions.cpp 2017-11-18 12:38:21.000000000 +0000 +++ primesieve-7.0+ds/src/console/cmdoptions.cpp 2018-06-08 08:51:41.000000000 +0000 @@ -3,15 +3,17 @@ /// @brief Parse command-line options for the primesieve console /// (terminal) application. /// -/// Copyright (C) 2017 Kim Walisch, +/// Copyright (C) 2018 Kim Walisch, /// /// This file is distributed under the BSD License. See the COPYING /// file in the top level directory. /// -#include #include "cmdoptions.hpp" -#include "calculator.hpp" + +#include +#include +#include #include #include @@ -95,12 +97,12 @@ switch (opt.getValue()) { - case 1: opts.flags |= PrimeSieve::PRINT_PRIMES; break; - case 2: opts.flags |= PrimeSieve::PRINT_TWINS; break; - case 3: opts.flags |= PrimeSieve::PRINT_TRIPLETS; break; - case 4: opts.flags |= PrimeSieve::PRINT_QUADRUPLETS; break; - case 5: opts.flags |= PrimeSieve::PRINT_QUINTUPLETS; break; - case 6: opts.flags |= PrimeSieve::PRINT_SEXTUPLETS; break; + case 1: opts.flags |= PRINT_PRIMES; break; + case 2: opts.flags |= PRINT_TWINS; break; + case 3: opts.flags |= PRINT_TRIPLETS; break; + case 4: opts.flags |= PRINT_QUADRUPLETS; break; + case 5: opts.flags |= PRINT_QUINTUPLETS; break; + case 6: opts.flags |= PRINT_SEXTUPLETS; break; default: throw primesieve_error("invalid option " + opt.str); } } @@ -118,19 +120,19 @@ { switch (n % 10) { - case 1: opts.flags |= PrimeSieve::COUNT_PRIMES; break; - case 2: opts.flags |= PrimeSieve::COUNT_TWINS; break; - case 3: opts.flags |= PrimeSieve::COUNT_TRIPLETS; break; - case 4: opts.flags |= PrimeSieve::COUNT_QUADRUPLETS; break; - case 5: opts.flags |= PrimeSieve::COUNT_QUINTUPLETS; break; - case 6: opts.flags |= PrimeSieve::COUNT_SEXTUPLETS; break; + case 1: opts.flags |= COUNT_PRIMES; break; + case 2: opts.flags |= COUNT_TWINS; break; + case 3: opts.flags |= COUNT_TRIPLETS; break; + case 4: opts.flags |= COUNT_QUADRUPLETS; break; + case 5: opts.flags |= COUNT_QUINTUPLETS; break; + case 6: opts.flags |= COUNT_SEXTUPLETS; break; default: throw primesieve_error("invalid option " + opt.str); } } } /// e.g. "--thread=4" -> return "--thread" -string getOption(string str) +string getOption(const string& str) { size_t pos = str.find_first_of("=0123456789"); @@ -141,7 +143,7 @@ } /// e.g. "--thread=4" -> return "4" -string getValue(string str) +string getValue(const string& str) { size_t pos = str.find_first_of("0123456789"); diff -Nru primesieve-6.3+ds/src/console/help.cpp primesieve-7.0+ds/src/console/help.cpp --- primesieve-6.3+ds/src/console/help.cpp 2017-11-18 12:38:21.000000000 +0000 +++ primesieve-7.0+ds/src/console/help.cpp 2018-06-08 08:51:41.000000000 +0000 @@ -3,7 +3,7 @@ /// @brief help() and version() functions of the primesieve /// console application. /// -/// Copyright (C) 2017 Kim Walisch, +/// Copyright (C) 2018 Kim Walisch, /// /// This file is distributed under the BSD License. See the COPYING /// file in the top level directory. @@ -61,11 +61,11 @@ void version() { cout << "primesieve " << primesieve::primesieve_version(); - cout << ", " << endl; - cout << "Copyright (C) 2010 - 2017 Kim Walisch" << endl; + cout << ", " << endl; + cout << "Copyright (C) 2010 - 2018 Kim Walisch" << endl; cout << endl; - cout << "BSD 2-Clause License " << endl; + cout << "BSD 2-Clause License " << endl; cout << endl; exit(0); diff -Nru primesieve-6.3+ds/src/console/main.cpp primesieve-7.0+ds/src/console/main.cpp --- primesieve-6.3+ds/src/console/main.cpp 2017-11-18 12:38:21.000000000 +0000 +++ primesieve-7.0+ds/src/console/main.cpp 2018-06-08 08:51:41.000000000 +0000 @@ -2,17 +2,16 @@ /// @file main.cpp /// @brief primesieve console application. /// -/// Copyright (C) 2017 Kim Walisch, +/// Copyright (C) 2018 Kim Walisch, /// /// This file is distributed under the BSD License. See the COPYING /// file in the top level directory. /// -#include +#include #include "cmdoptions.hpp" #include -#include #include #include #include @@ -23,11 +22,11 @@ namespace { -void printResults(ParallelPrimeSieve& ps, CmdOptions& opt) +void printResults(ParallelSieve& ps, CmdOptions& opt) { cout << left; - const string text[] = + const string text[6] = { "Primes: ", "Twin primes: ", @@ -48,7 +47,7 @@ /// Count & print primes and prime k-tuplets void sieve(CmdOptions& opt) { - ParallelPrimeSieve ps; + ParallelSieve ps; auto& numbers = opt.numbers; if (opt.flags) @@ -72,7 +71,7 @@ } if (opt.status) - ps.addFlags(ps.PRINT_STATUS); + ps.addFlags(PRINT_STATUS); ps.sieve(); printResults(ps, opt); @@ -80,7 +79,7 @@ void nthPrime(CmdOptions& opt) { - ParallelPrimeSieve ps; + ParallelSieve ps; auto& numbers = opt.numbers; if (opt.flags) diff -Nru primesieve-6.3+ds/src/CpuInfo.cpp primesieve-7.0+ds/src/CpuInfo.cpp --- primesieve-6.3+ds/src/CpuInfo.cpp 1970-01-01 00:00:00.000000000 +0000 +++ primesieve-7.0+ds/src/CpuInfo.cpp 2018-06-08 08:51:41.000000000 +0000 @@ -0,0 +1,344 @@ +/// +/// @file CpuInfo.cpp +/// @brief Get the CPUs' cache sizes in bytes +/// +/// Copyright (C) 2018 Kim Walisch, +/// +/// This file is distributed under the BSD License. See the COPYING +/// file in the top level directory. +/// + +#include + +#include +#include +#include + +#if defined(__APPLE__) + #if !defined(__has_include) + #define APPLE_SYSCTL + #elif __has_include() && \ + __has_include() + #define APPLE_SYSCTL + #endif +#endif + +#if defined(_WIN32) + +#include +#include + +#elif defined(APPLE_SYSCTL) + +#include +#include +#include + +#else // all other OSes + +#include +#include + +using namespace std; + +namespace { + +string getString(const string& filename) +{ + ifstream file(filename); + string str; + + if (file) + { + // https://stackoverflow.com/a/3177560/363778 + stringstream trimmer; + trimmer << file.rdbuf(); + trimmer >> str; + } + + return str; +} + +size_t getValue(const string& filename) +{ + size_t val = 0; + string str = getString(filename); + + if (!str.empty()) + { + val = stol(str); + + // Last character may be: + // 'K' = kilobytes + // 'M' = megabytes + // 'G' = gigabytes + if (str.back() == 'K') + val *= 1024; + if (str.back() == 'M') + val *= 1024 * 1024; + if (str.back() == 'G') + val *= 1024 * 1024 * 1024; + } + + return val; +} + +} // namespace + +#endif + +using namespace std; + +namespace primesieve { + +CpuInfo::CpuInfo() + : l1CacheSize_(0), + l2CacheSize_(0), + privateL2Cache_(false) +{ + try + { + init(); + } + catch (exception& e) + { + error_ = e.what(); + } +} + +size_t CpuInfo::l1CacheSize() const +{ + return l1CacheSize_; +} + +size_t CpuInfo::l2CacheSize() const +{ + return l2CacheSize_; +} + +bool CpuInfo::privateL2Cache() const +{ + return privateL2Cache_; +} + +string CpuInfo::getError() const +{ + return error_; +} + +bool CpuInfo::hasL1Cache() const +{ + return l1CacheSize_ >= (1 << 12) && + l1CacheSize_ <= (1 << 30); +} + +bool CpuInfo::hasL2Cache() const +{ + return l2CacheSize_ >= (1 << 12) && + l2CacheSize_ <= (1 << 30); +} + +#if defined(APPLE_SYSCTL) + +void CpuInfo::init() +{ + size_t l1Length = sizeof(l1CacheSize_); + size_t l2Length = sizeof(l2CacheSize_); + + sysctlbyname("hw.l1dcachesize", &l1CacheSize_, &l1Length, NULL, 0); + sysctlbyname("hw.l2cachesize" , &l2CacheSize_, &l2Length, NULL, 0); + + size_t size = 0; + + if (!sysctlbyname("hw.cacheconfig", NULL, &size, NULL, 0)) + { + size_t n = size / sizeof(size); + vector cacheconfig(n); + + if (cacheconfig.size() > 2) + { + // https://developer.apple.com/library/content/releasenotes/Performance/RN-AffinityAPI/index.html + sysctlbyname("hw.cacheconfig" , &cacheconfig[0], &size, NULL, 0); + size_t l2Sharing = cacheconfig[2]; + + if (l2Sharing <= 1) + privateL2Cache_ = true; + else + { + size_t logicalcpu = 1; + size = sizeof(size); + sysctlbyname("hw.logicalcpu", &logicalcpu, &size, NULL, 0); + logicalcpu = max(1, logicalcpu); + + size_t physicalcpu = 1; + size = sizeof(size); + sysctlbyname("hw.physicalcpu", &physicalcpu, &size, NULL, 0); + physicalcpu = max(1, physicalcpu); + + if (l2Sharing <= logicalcpu / physicalcpu) + privateL2Cache_ = true; + } + } + } +} + +#elif defined(_WIN32) + +void CpuInfo::init() +{ + typedef BOOL (WINAPI *LPFN_GLPI)(PSYSTEM_LOGICAL_PROCESSOR_INFORMATION, PDWORD); + + LPFN_GLPI glpi = (LPFN_GLPI) GetProcAddress(GetModuleHandle(TEXT("kernel32")), "GetLogicalProcessorInformation"); + + if (!glpi) + return; + + DWORD bytes = 0; + glpi(0, &bytes); + + if (!bytes) + return; + + size_t threadsPerCore = 0; + size_t size = bytes / sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION); + vector info(size); + + if (!glpi(&info[0], &bytes)) + return; + + for (size_t i = 0; i < size; i++) + { + if (info[i].Relationship == RelationProcessorCore) + { + auto mask = info[i].ProcessorMask; + + // ProcessorMask contains one bit set for + // each logical CPU core related to the + // current physical CPU core + for (threadsPerCore = 0; mask > 0; threadsPerCore++) + mask &= mask - 1; + } + + if (info[i].Relationship == RelationCache && + (info[i].Cache.Type == CacheData || + info[i].Cache.Type == CacheUnified)) + { + if (info[i].Cache.Level == 1) + l1CacheSize_ = info[i].Cache.Size; + if (info[i].Cache.Level == 2) + l2CacheSize_ = info[i].Cache.Size; + + // if the CPU has an L3 cache we assume + // the L2 cache is private + if (info[i].Cache.Level == 3 && + info[i].Cache.Size > 0) + privateL2Cache_ = true; + } + } + +// Windows 7 (2009) or later +#if _WIN32_WINNT >= 0x0601 + + typedef BOOL (WINAPI *LPFN_GLPIEX)(LOGICAL_PROCESSOR_RELATIONSHIP, PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX, PDWORD); + + LPFN_GLPIEX glpiex = (LPFN_GLPIEX) GetProcAddress( + GetModuleHandle(TEXT("kernel32")), "GetLogicalProcessorInformationEx"); + + if (!glpiex) + return; + + bytes = 0; + glpiex(RelationAll, 0, &bytes); + + if (!bytes) + return; + + vector buffer(bytes); + SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX* cpu; + + if (!glpiex(RelationAll, (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX*) &buffer[0], &bytes)) + return; + + for (size_t i = 0; i < bytes; i += cpu->Size) + { + cpu = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX*) &buffer[i]; + + // check L2 cache + if (cpu->Relationship == RelationCache && + cpu->Cache.GroupMask.Group == 0 && + cpu->Cache.Level == 2 && + (cpu->Cache.Type == CacheData || + cpu->Cache.Type == CacheUnified)) + { + // @warning: GetLogicalProcessorInformationEx() reports + // incorrect data when Windows is run inside a virtual + // machine. Specifically the GROUP_AFFINITY.Mask will + // only have 1 or 2 bits set for each CPU cache (L1, L2 and + // L3) even if more logical CPU cores share the cache + auto mask = cpu->Cache.GroupMask.Mask; + size_t l2Sharing = 0; + + // Cache.GroupMask.Mask contains one bit set for + // each logical CPU core sharing the cache + for (; mask > 0; l2Sharing++) + mask &= mask - 1; + + // the L2 cache is private if it is tied to a physical CPU core + privateL2Cache_ = (l2Sharing <= threadsPerCore); + + break; + } + } + +#endif +} + +#else + +/// This works on Linux and Android. We also use this +/// for all unknown OSes, it might work. +/// +void CpuInfo::init() +{ + for (int i = 0; i <= 3; i++) + { + string filename = "/sys/devices/system/cpu/cpu0/cache/index" + to_string(i); + string threadSiblingsList = "/sys/devices/system/cpu/cpu0/topology/thread_siblings_list"; + + string cacheLevel = filename + "/level"; + string cacheSize = filename + "/size"; + string sharedCpuList = filename + "/shared_cpu_list"; + string cacheType = filename + "/type"; + + size_t level = getValue(cacheLevel); + string type = getString(cacheType); + + if (level == 1 && + (type == "Data" || + type == "Unified")) + { + l1CacheSize_ = getValue(cacheSize); + } + + if (level == 2 && + (type == "Data" || + type == "Unified")) + { + l2CacheSize_ = getValue(cacheSize); + sharedCpuList = getString(sharedCpuList); + threadSiblingsList = getString(threadSiblingsList); + + // https://lwn.net/Articles/254445/ + if (!sharedCpuList.empty() && + sharedCpuList == threadSiblingsList) + privateL2Cache_ = true; + } + } +} + +#endif + +/// Singleton +const CpuInfo cpuInfo; + +} // namespace diff -Nru primesieve-6.3+ds/src/EratBig.cpp primesieve-7.0+ds/src/EratBig.cpp --- primesieve-6.3+ds/src/EratBig.cpp 1970-01-01 00:00:00.000000000 +0000 +++ primesieve-7.0+ds/src/EratBig.cpp 2018-06-08 08:51:41.000000000 +0000 @@ -0,0 +1,185 @@ +/// +/// @file EratBig.cpp +/// @brief Segmented sieve of Eratosthenes optimized for big sieving +/// primes. This is an optimized implementation of Tomas +/// Oliveira e Silva's cache-friendly bucket sieve algorithm: +/// http://www.ieeta.pt/~tos/software/prime_sieve.html +/// +/// Copyright (C) 2018 Kim Walisch, +/// +/// This file is distributed under the BSD License. See the COPYING +/// file in the top level directory. +/// + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +using namespace std; + +namespace primesieve { + +/// @stop: Upper bound for sieving +/// @sieveSize: Sieve size in bytes +/// @maxPrime: Sieving primes <= maxPrime +/// +void EratBig::init(uint64_t stop, uint64_t sieveSize, uint64_t maxPrime) +{ + // '>> log2SieveSize' requires power of 2 sieveSize + if (!isPow2(sieveSize)) + throw primesieve_error("EratBig: sieveSize must be a power of 2"); + + enabled_ = true; + maxPrime_ = maxPrime; + log2SieveSize_ = ilog2(sieveSize); + moduloSieveSize_ = sieveSize - 1; + stock_ = nullptr; + + Wheel::init(stop, sieveSize); + init(sieveSize); +} + +void EratBig::init(uint64_t sieveSize) +{ + uint64_t maxSievingPrime = maxPrime_ / 30; + uint64_t maxNextMultiple = maxSievingPrime * getMaxFactor() + getMaxFactor(); + uint64_t maxMultipleIndex = sieveSize - 1 + maxNextMultiple; + uint64_t maxSegmentCount = maxMultipleIndex >> log2SieveSize_; + uint64_t size = maxSegmentCount + 1; + + // EratBig uses up to 1.6 gigabytes of memory + uint64_t maxBytes = (1u << 30) * 2; + memory_.reserve(maxBytes / config::BYTES_PER_ALLOC); + + lists_.resize(size, nullptr); + for (uint64_t i = 0; i < size; i++) + pushBucket(i); +} + +/// Add a new sieving prime to EratBig +void EratBig::storeSievingPrime(uint64_t prime, uint64_t multipleIndex, uint64_t wheelIndex) +{ + assert(prime <= maxPrime_); + uint64_t sievingPrime = prime / 30; + uint64_t segment = multipleIndex >> log2SieveSize_; + multipleIndex &= moduloSieveSize_; + + if (!lists_[segment]->store(sievingPrime, multipleIndex, wheelIndex)) + pushBucket(segment); +} + +/// Add an empty bucket to the front of lists_[segment] +void EratBig::pushBucket(uint64_t segment) +{ + // allocate new buckets + if (!stock_) + { + int N = config::BYTES_PER_ALLOC / sizeof(Bucket); + memory_.emplace_back(unique_ptr(new Bucket[N])); + Bucket* bucket = memory_.back().get(); + + for (int i = 0; i < N - 1; i++) + bucket[i].setNext(&bucket[i + 1]); + bucket[N-1].setNext(nullptr); + stock_ = bucket; + } + Bucket* empty = stock_; + stock_ = stock_->next(); + moveBucket(*empty, lists_[segment]); +} + +void EratBig::moveBucket(Bucket& src, Bucket*& dest) +{ + src.setNext(dest); + dest = &src; +} + +/// Cross-off the multiples of big sieving +/// primes from the sieve array +/// +void EratBig::crossOff(byte_t* sieve) +{ + while (lists_[0]->hasNext() || !lists_[0]->empty()) + { + Bucket* bucket = lists_[0]; + lists_[0] = nullptr; + pushBucket(0); + do { + crossOff(sieve, bucket->begin(), bucket->end()); + Bucket* processed = bucket; + bucket = bucket->next(); + processed->reset(); + moveBucket(*processed, stock_); + } while (bucket); + } + + rotate(lists_.begin(), lists_.begin() + 1, lists_.end()); +} + +/// Segmented sieve of Eratosthenes with wheel factorization +/// optimized for big sieving primes that have very few +/// multiples per segment. Cross-off the next multiple of +/// each sieving prime in the current bucket +/// +void EratBig::crossOff(byte_t* sieve, SievingPrime* primes, SievingPrime* end) +{ + Bucket** lists = &lists_[0]; + uint64_t moduloSieveSize = moduloSieveSize_; + uint64_t log2SieveSize = log2SieveSize_; + + // 2 sieving primes are processed per loop iteration + // to increase instruction level parallelism + for (; primes + 2 <= end; primes += 2) + { + uint64_t multipleIndex0 = primes[0].getMultipleIndex(); + uint64_t wheelIndex0 = primes[0].getWheelIndex(); + uint64_t sievingPrime0 = primes[0].getSievingPrime(); + uint64_t multipleIndex1 = primes[1].getMultipleIndex(); + uint64_t wheelIndex1 = primes[1].getWheelIndex(); + uint64_t sievingPrime1 = primes[1].getSievingPrime(); + + // cross-off the current multiple (unset bit) + // and calculate the next multiple + unsetBit(sieve, sievingPrime0, &multipleIndex0, &wheelIndex0); + unsetBit(sieve, sievingPrime1, &multipleIndex1, &wheelIndex1); + + uint64_t segment0 = multipleIndex0 >> log2SieveSize; + uint64_t segment1 = multipleIndex1 >> log2SieveSize; + + multipleIndex0 &= moduloSieveSize; + multipleIndex1 &= moduloSieveSize; + + // move the 2 sieving primes to the list related + // to their next multiple + if (!lists[segment0]->store(sievingPrime0, multipleIndex0, wheelIndex0)) + pushBucket(segment0); + if (!lists[segment1]->store(sievingPrime1, multipleIndex1, wheelIndex1)) + pushBucket(segment1); + } + + if (primes != end) + { + uint64_t multipleIndex = primes->getMultipleIndex(); + uint64_t wheelIndex = primes->getWheelIndex(); + uint64_t sievingPrime = primes->getSievingPrime(); + + unsetBit(sieve, sievingPrime, &multipleIndex, &wheelIndex); + uint64_t segment = multipleIndex >> log2SieveSize; + multipleIndex &= moduloSieveSize; + + if (!lists[segment]->store(sievingPrime, multipleIndex, wheelIndex)) + pushBucket(segment); + } +} + +} // namespace diff -Nru primesieve-6.3+ds/src/Erat.cpp primesieve-7.0+ds/src/Erat.cpp --- primesieve-6.3+ds/src/Erat.cpp 1970-01-01 00:00:00.000000000 +0000 +++ primesieve-7.0+ds/src/Erat.cpp 2018-06-08 08:51:41.000000000 +0000 @@ -0,0 +1,208 @@ +/// +/// @file Erat.cpp +/// @brief The Erat class manages prime sieving using the +/// EratSmall, EratMedium, EratBig classes. +/// +/// Copyright (C) 2018 Kim Walisch, +/// +/// This file is distributed under the BSD License. See the COPYING +/// file in the top level directory. +/// + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +using namespace std; +using namespace primesieve; + +namespace { + +/// unset bits < start +const array unsetSmaller = +{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xfe, 0xfe, 0xfe, 0xfe, 0xfc, 0xfc, 0xf8, 0xf8, + 0xf8, 0xf8, 0xf0, 0xf0, 0xe0, 0xe0, 0xe0, 0xe0, + 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0x80, 0x80, + 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +/// unset bits > stop +const array unsetLarger = +{ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x01, 0x01, 0x01, 0x03, 0x03, 0x07, 0x07, 0x07, + 0x07, 0x0f, 0x0f, 0x1f, 0x1f, 0x1f, 0x1f, 0x3f, + 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x7f, 0x7f, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff +}; + +} // namespace + +namespace primesieve { + +const array Erat::bruijnBitValues_ = +{ + 7, 47, 11, 49, 67, 113, 13, 53, + 89, 71, 161, 101, 119, 187, 17, 233, + 59, 79, 91, 73, 133, 139, 163, 103, + 149, 121, 203, 169, 191, 217, 19, 239, + 43, 61, 109, 83, 157, 97, 181, 229, + 77, 131, 137, 143, 199, 167, 211, 41, + 107, 151, 179, 227, 127, 197, 209, 37, + 173, 223, 193, 31, 221, 29, 23, 241 +}; + +Erat::Erat() { } + +Erat::Erat(uint64_t start, uint64_t stop) : + start_(start), + stop_(stop) +{ } + +Erat::~Erat() { } + +/// @start: Sieve primes >= start +/// @stop: Sieve primes <= stop +/// @sieveSize: Sieve size in kilobytes +/// @preSieve: Pre-sieve primes +/// +void Erat::init(uint64_t start, + uint64_t stop, + uint64_t sieveSize, + PreSieve& preSieve) +{ + if (start > stop) + return; + + if (start < 7) + throw primesieve_error("Erat: start must be >= 7"); + + start_ = start; + stop_ = stop; + preSieve_ = &preSieve; + maxPreSieve_ = preSieve.getMaxPrime(); + initSieve(sieveSize); + + uint64_t rem = byteRemainder(start); + uint64_t dist = sieveSize_ * 30 + 6; + segmentLow_ = start_ - rem; + segmentHigh_ = checkedAdd(segmentLow_, dist); + segmentHigh_ = min(segmentHigh_, stop); + + initErat(); +} + +void Erat::initSieve(uint64_t sieveSize) +{ + sieveSize_ = floorPow2(sieveSize); + sieveSize_ = inBetween(8, sieveSize_, 4096); + sieveSize_ *= 1024; + + sieve_ = new byte_t[sieveSize_]; + deleter_.reset(sieve_); +} + +void Erat::initErat() +{ + uint64_t sqrtStop = isqrt(stop_); + uint64_t l1Size = EratSmall::getL1Size(sieveSize_); + + maxEratSmall_ = (uint64_t) (l1Size * config::FACTOR_ERATSMALL); + maxEratMedium_ = (uint64_t) (sieveSize_ * config::FACTOR_ERATMEDIUM); + + if (sqrtStop > maxPreSieve_) + eratSmall_.init(stop_, l1Size, maxEratSmall_); + if (sqrtStop > maxEratSmall_) + eratMedium_.init(stop_, sieveSize_, maxEratMedium_); + if (sqrtStop > maxEratMedium_) + eratBig_.init(stop_, sieveSize_, sqrtStop); +} + +bool Erat::hasNextSegment() const +{ + return segmentLow_ < stop_; +} + +uint64_t Erat::byteRemainder(uint64_t n) +{ + n %= 30; + if (n <= 6) n += 30; + return n; +} + +/// Pre-sieve multiples of small primes e.g. <= 19 +/// to speed up the sieve of Eratosthenes +/// +void Erat::preSieve() +{ + preSieve_->copy(sieve_, sieveSize_, segmentLow_); + + // unset bits < start + if (segmentLow_ <= start_) + { + if (start_ <= maxPreSieve_) + sieve_[0] = 0xff; + uint64_t rem = byteRemainder(start_); + sieve_[0] &= unsetSmaller[rem]; + } +} + +void Erat::crossOff() +{ + if (eratSmall_.enabled()) + eratSmall_.crossOff(sieve_, sieveSize_); + if (eratMedium_.enabled()) + eratMedium_.crossOff(sieve_, sieveSize_); + if (eratBig_.enabled()) + eratBig_.crossOff(sieve_); +} + +void Erat::sieveSegment() +{ + if (segmentHigh_ == stop_) + sieveLastSegment(); + else + { + preSieve(); + crossOff(); + + uint64_t dist = sieveSize_ * 30; + segmentLow_ = checkedAdd(segmentLow_, dist); + segmentHigh_ = checkedAdd(segmentHigh_, dist); + segmentHigh_ = min(segmentHigh_, stop_); + } +} + +void Erat::sieveLastSegment() +{ + uint64_t rem = byteRemainder(stop_); + uint64_t dist = (stop_ - rem) - segmentLow_; + sieveSize_ = dist / 30 + 1; + + preSieve(); + crossOff(); + + // unset bits > stop + sieve_[sieveSize_ - 1] &= unsetLarger[rem]; + + // unset bytes > stop + uint64_t bytes = sieveSize_ % 8; + bytes = (8 - bytes) % 8; + fill_n(&sieve_[sieveSize_], bytes, 0); + + segmentLow_ = stop_; +} + +} // namespace diff -Nru primesieve-6.3+ds/src/EratMedium.cpp primesieve-7.0+ds/src/EratMedium.cpp --- primesieve-6.3+ds/src/EratMedium.cpp 1970-01-01 00:00:00.000000000 +0000 +++ primesieve-7.0+ds/src/EratMedium.cpp 2018-06-08 08:51:41.000000000 +0000 @@ -0,0 +1,115 @@ +/// +/// @file EratMedium.cpp +/// @brief Segmented sieve of Eratosthenes optimized for +/// medium sieving primes. +/// +/// Copyright (C) 2018 Kim Walisch, +/// +/// This file is distributed under the BSD License. See the COPYING +/// file in the top level directory. +/// + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +namespace primesieve { + +/// @stop: Upper bound for sieving +/// @sieveSize: Sieve size in bytes +/// @maxPrime: Sieving primes <= maxPrime +/// +void EratMedium::init(uint64_t stop, uint64_t sieveSize, uint64_t maxPrime) +{ + uint64_t maxSieveSize = 4096 << 10; + + if (sieveSize > maxSieveSize) + throw primesieve_error("EratMedium: sieveSize must be <= 4096 kilobytes"); + if (maxPrime > sieveSize * 5) + throw primesieve_error("EratMedium: maxPrime must be <= sieveSize * 5"); + + enabled_ = true; + maxPrime_ = maxPrime; + Wheel::init(stop, sieveSize); + + size_t size = primeCountApprox(maxPrime); + primes_.reserve(size); +} + +/// Add a new sieving prime to EratMedium +void EratMedium::storeSievingPrime(uint64_t prime, uint64_t multipleIndex, uint64_t wheelIndex) +{ + assert(prime <= maxPrime_); + uint64_t sievingPrime = prime / 30; + primes_.emplace_back(sievingPrime, multipleIndex, wheelIndex); +} + +/// Segmented sieve of Eratosthenes with wheel factorization +/// optimized for medium sieving primes that have a +/// few multiples per segment +/// +void EratMedium::crossOff(byte_t* sieve, uint64_t sieveSize) +{ + size_t i = 0; + size_t size = primes_.size(); + auto primes = primes_.data(); + + // process 3 sieving primes per loop iteration to + // increase instruction level parallelism + for (; i < size - size % 3; i += 3) + { + uint64_t multipleIndex0 = primes[i + 0].getMultipleIndex(); + uint64_t wheelIndex0 = primes[i + 0].getWheelIndex(); + uint64_t sievingPrime0 = primes[i + 0].getSievingPrime(); + uint64_t multipleIndex1 = primes[i + 1].getMultipleIndex(); + uint64_t wheelIndex1 = primes[i + 1].getWheelIndex(); + uint64_t sievingPrime1 = primes[i + 1].getSievingPrime(); + uint64_t multipleIndex2 = primes[i + 2].getMultipleIndex(); + uint64_t wheelIndex2 = primes[i + 2].getWheelIndex(); + uint64_t sievingPrime2 = primes[i + 2].getSievingPrime(); + + while (multipleIndex0 < sieveSize) + { + unsetBit(sieve, sievingPrime0, &multipleIndex0, &wheelIndex0); + if (multipleIndex1 >= sieveSize) break; + unsetBit(sieve, sievingPrime1, &multipleIndex1, &wheelIndex1); + if (multipleIndex2 >= sieveSize) break; + unsetBit(sieve, sievingPrime2, &multipleIndex2, &wheelIndex2); + } + + while (multipleIndex0 < sieveSize) unsetBit(sieve, sievingPrime0, &multipleIndex0, &wheelIndex0); + while (multipleIndex1 < sieveSize) unsetBit(sieve, sievingPrime1, &multipleIndex1, &wheelIndex1); + while (multipleIndex2 < sieveSize) unsetBit(sieve, sievingPrime2, &multipleIndex2, &wheelIndex2); + + multipleIndex0 -= sieveSize; + multipleIndex1 -= sieveSize; + multipleIndex2 -= sieveSize; + + primes[i + 0].set(multipleIndex0, wheelIndex0); + primes[i + 1].set(multipleIndex1, wheelIndex1); + primes[i + 2].set(multipleIndex2, wheelIndex2); + } + + // process remaining sieving primes + for (; i < size; i++) + { + uint64_t multipleIndex = primes[i].getMultipleIndex(); + uint64_t wheelIndex = primes[i].getWheelIndex(); + uint64_t sievingPrime = primes[i].getSievingPrime(); + + while (multipleIndex < sieveSize) + unsetBit(sieve, sievingPrime, &multipleIndex, &wheelIndex); + + multipleIndex -= sieveSize; + primes[i].set(multipleIndex, wheelIndex); + } +} + +} // namespace diff -Nru primesieve-6.3+ds/src/EratSmall.cpp primesieve-7.0+ds/src/EratSmall.cpp --- primesieve-6.3+ds/src/EratSmall.cpp 1970-01-01 00:00:00.000000000 +0000 +++ primesieve-7.0+ds/src/EratSmall.cpp 2018-06-08 08:51:41.000000000 +0000 @@ -0,0 +1,368 @@ +/// +/// @file EratSmall.cpp +/// @brief Segmented sieve of Eratosthenes optimized for +/// small sieving primes. +/// +/// Copyright (C) 2018 Kim Walisch, +/// +/// This file is distributed under the BSD License. See the COPYING +/// file in the top level directory. +/// + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +using namespace std; + +namespace primesieve { + +/// @stop: Upper bound for sieving +/// @l1Size: Sieve size in bytes +/// @maxPrime: Sieving primes <= maxPrime +/// +void EratSmall::init(uint64_t stop, uint64_t l1Size, uint64_t maxPrime) +{ + if (maxPrime > l1Size * 3) + throw primesieve_error("EratSmall: maxPrime must be <= l1Size * 3"); + + enabled_ = true; + maxPrime_ = maxPrime; + l1Size_ = l1Size; + Wheel::init(stop, l1Size); + + size_t count = primeCountApprox(maxPrime); + primes_.reserve(count); +} + +/// Usually sieve size = L2 cache size, +/// but EratSmall runs faster using +/// sieve size = L1 cache size +/// +uint64_t EratSmall::getL1Size(uint64_t sieveSize) +{ + if (!cpuInfo.hasL1Cache()) + return sieveSize; + + uint64_t size = cpuInfo.l1CacheSize(); + uint64_t minSize = 8 << 10; + uint64_t maxSize = 4096 << 10; + + size = inBetween(minSize, size, maxSize); + + return size; +} + +/// Add a new sieving prime to EratSmall +void EratSmall::storeSievingPrime(uint64_t prime, uint64_t multipleIndex, uint64_t wheelIndex) +{ + assert(prime <= maxPrime_); + uint64_t sievingPrime = prime / 30; + primes_.emplace_back(sievingPrime, multipleIndex, wheelIndex); +} + +/// Cross-off the multiples of small sieving +/// primes from the sieve array +/// +void EratSmall::crossOff(byte_t* sieve, uint64_t sieveSize) +{ + byte_t* sieveEnd = sieve + sieveSize; + + while (sieve < sieveEnd) + { + byte_t* start = sieve; + sieve += l1Size_; + sieve = min(sieve, sieveEnd); + crossOff(start, sieve); + } +} + +/// Segmented sieve of Eratosthenes with wheel factorization +/// optimized for small sieving primes that have many multiples +/// per segment. This algorithm uses a hardcoded modulo 30 +/// wheel that skips multiples of 2, 3 and 5 +/// +void EratSmall::crossOff(byte_t* sieve, byte_t* sieveEnd) +{ + for (auto& prime : primes_) + { + uint64_t sievingPrime = prime.getSievingPrime(); + uint64_t multipleIndex = prime.getMultipleIndex(); + uint64_t wheelIndex = prime.getWheelIndex(); + + // pointer to the byte containing the first multiple + // of sievingPrime within the current segment + byte_t* p = &sieve[multipleIndex]; + byte_t* loopLimit = sieveEnd - (sievingPrime * 28 + 27); + if (loopLimit > sieveEnd) + loopLimit = p; + + switch (wheelIndex) + { + for (;;) // i*30 + 7 + { + case 0: // each iteration removes the next 8 multiples + // of the current sievingPrime + for (; p < loopLimit; p += sievingPrime * 30 + 7) + { + p[sievingPrime * 0 + 0] &= BIT0; + p[sievingPrime * 6 + 1] &= BIT4; + p[sievingPrime * 10 + 2] &= BIT3; + p[sievingPrime * 12 + 2] &= BIT7; + p[sievingPrime * 16 + 3] &= BIT6; + p[sievingPrime * 18 + 4] &= BIT2; + p[sievingPrime * 22 + 5] &= BIT1; + p[sievingPrime * 28 + 6] &= BIT5; + } + if (p >= sieveEnd) { prime.setWheelIndex(0); break; } + *p &= BIT0; p += sievingPrime * 6 + 1; + case 1: if (p >= sieveEnd) { prime.setWheelIndex(1); break; } + *p &= BIT4; p += sievingPrime * 4 + 1; + case 2: if (p >= sieveEnd) { prime.setWheelIndex(2); break; } + *p &= BIT3; p += sievingPrime * 2 + 0; + case 3: if (p >= sieveEnd) { prime.setWheelIndex(3); break; } + *p &= BIT7; p += sievingPrime * 4 + 1; + case 4: if (p >= sieveEnd) { prime.setWheelIndex(4); break; } + *p &= BIT6; p += sievingPrime * 2 + 1; + case 5: if (p >= sieveEnd) { prime.setWheelIndex(5); break; } + *p &= BIT2; p += sievingPrime * 4 + 1; + case 6: if (p >= sieveEnd) { prime.setWheelIndex(6); break; } + *p &= BIT1; p += sievingPrime * 6 + 1; + case 7: if (p >= sieveEnd) { prime.setWheelIndex(7); break; } + *p &= BIT5; p += sievingPrime * 2 + 1; + } + break; + for (;;) // i*30 + 11 + { + case 8: for (; p < loopLimit; p += sievingPrime * 30 + 11) + { + p[sievingPrime * 0 + 0] &= BIT1; + p[sievingPrime * 6 + 2] &= BIT3; + p[sievingPrime * 10 + 3] &= BIT7; + p[sievingPrime * 12 + 4] &= BIT5; + p[sievingPrime * 16 + 6] &= BIT0; + p[sievingPrime * 18 + 6] &= BIT6; + p[sievingPrime * 22 + 8] &= BIT2; + p[sievingPrime * 28 + 10] &= BIT4; + } + if (p >= sieveEnd) { prime.setWheelIndex(8); break; } + *p &= BIT1; p += sievingPrime * 6 + 2; + case 9: if (p >= sieveEnd) { prime.setWheelIndex(9); break; } + *p &= BIT3; p += sievingPrime * 4 + 1; + case 10: if (p >= sieveEnd) { prime.setWheelIndex(10); break; } + *p &= BIT7; p += sievingPrime * 2 + 1; + case 11: if (p >= sieveEnd) { prime.setWheelIndex(11); break; } + *p &= BIT5; p += sievingPrime * 4 + 2; + case 12: if (p >= sieveEnd) { prime.setWheelIndex(12); break; } + *p &= BIT0; p += sievingPrime * 2 + 0; + case 13: if (p >= sieveEnd) { prime.setWheelIndex(13); break; } + *p &= BIT6; p += sievingPrime * 4 + 2; + case 14: if (p >= sieveEnd) { prime.setWheelIndex(14); break; } + *p &= BIT2; p += sievingPrime * 6 + 2; + case 15: if (p >= sieveEnd) { prime.setWheelIndex(15); break; } + *p &= BIT4; p += sievingPrime * 2 + 1; + } + break; + for (;;) // i*30 + 13 + { + case 16: for (; p < loopLimit; p += sievingPrime * 30 + 13) + { + p[sievingPrime * 0 + 0] &= BIT2; + p[sievingPrime * 6 + 2] &= BIT7; + p[sievingPrime * 10 + 4] &= BIT5; + p[sievingPrime * 12 + 5] &= BIT4; + p[sievingPrime * 16 + 7] &= BIT1; + p[sievingPrime * 18 + 8] &= BIT0; + p[sievingPrime * 22 + 9] &= BIT6; + p[sievingPrime * 28 + 12] &= BIT3; + } + if (p >= sieveEnd) { prime.setWheelIndex(16); break; } + *p &= BIT2; p += sievingPrime * 6 + 2; + case 17: if (p >= sieveEnd) { prime.setWheelIndex(17); break; } + *p &= BIT7; p += sievingPrime * 4 + 2; + case 18: if (p >= sieveEnd) { prime.setWheelIndex(18); break; } + *p &= BIT5; p += sievingPrime * 2 + 1; + case 19: if (p >= sieveEnd) { prime.setWheelIndex(19); break; } + *p &= BIT4; p += sievingPrime * 4 + 2; + case 20: if (p >= sieveEnd) { prime.setWheelIndex(20); break; } + *p &= BIT1; p += sievingPrime * 2 + 1; + case 21: if (p >= sieveEnd) { prime.setWheelIndex(21); break; } + *p &= BIT0; p += sievingPrime * 4 + 1; + case 22: if (p >= sieveEnd) { prime.setWheelIndex(22); break; } + *p &= BIT6; p += sievingPrime * 6 + 3; + case 23: if (p >= sieveEnd) { prime.setWheelIndex(23); break; } + *p &= BIT3; p += sievingPrime * 2 + 1; + } + break; + for (;;) // i*30 + 17 + { + case 24: for (; p < loopLimit; p += sievingPrime * 30 + 17) + { + p[sievingPrime * 0 + 0] &= BIT3; + p[sievingPrime * 6 + 3] &= BIT6; + p[sievingPrime * 10 + 6] &= BIT0; + p[sievingPrime * 12 + 7] &= BIT1; + p[sievingPrime * 16 + 9] &= BIT4; + p[sievingPrime * 18 + 10] &= BIT5; + p[sievingPrime * 22 + 12] &= BIT7; + p[sievingPrime * 28 + 16] &= BIT2; + } + if (p >= sieveEnd) { prime.setWheelIndex(24); break; } + *p &= BIT3; p += sievingPrime * 6 + 3; + case 25: if (p >= sieveEnd) { prime.setWheelIndex(25); break; } + *p &= BIT6; p += sievingPrime * 4 + 3; + case 26: if (p >= sieveEnd) { prime.setWheelIndex(26); break; } + *p &= BIT0; p += sievingPrime * 2 + 1; + case 27: if (p >= sieveEnd) { prime.setWheelIndex(27); break; } + *p &= BIT1; p += sievingPrime * 4 + 2; + case 28: if (p >= sieveEnd) { prime.setWheelIndex(28); break; } + *p &= BIT4; p += sievingPrime * 2 + 1; + case 29: if (p >= sieveEnd) { prime.setWheelIndex(29); break; } + *p &= BIT5; p += sievingPrime * 4 + 2; + case 30: if (p >= sieveEnd) { prime.setWheelIndex(30); break; } + *p &= BIT7; p += sievingPrime * 6 + 4; + case 31: if (p >= sieveEnd) { prime.setWheelIndex(31); break; } + *p &= BIT2; p += sievingPrime * 2 + 1; + } + break; + for (;;) // i*30 + 19 + { + case 32: for (; p < loopLimit; p += sievingPrime * 30 + 19) + { + p[sievingPrime * 0 + 0] &= BIT4; + p[sievingPrime * 6 + 4] &= BIT2; + p[sievingPrime * 10 + 6] &= BIT6; + p[sievingPrime * 12 + 8] &= BIT0; + p[sievingPrime * 16 + 10] &= BIT5; + p[sievingPrime * 18 + 11] &= BIT7; + p[sievingPrime * 22 + 14] &= BIT3; + p[sievingPrime * 28 + 18] &= BIT1; + } + if (p >= sieveEnd) { prime.setWheelIndex(32); break; } + *p &= BIT4; p += sievingPrime * 6 + 4; + case 33: if (p >= sieveEnd) { prime.setWheelIndex(33); break; } + *p &= BIT2; p += sievingPrime * 4 + 2; + case 34: if (p >= sieveEnd) { prime.setWheelIndex(34); break; } + *p &= BIT6; p += sievingPrime * 2 + 2; + case 35: if (p >= sieveEnd) { prime.setWheelIndex(35); break; } + *p &= BIT0; p += sievingPrime * 4 + 2; + case 36: if (p >= sieveEnd) { prime.setWheelIndex(36); break; } + *p &= BIT5; p += sievingPrime * 2 + 1; + case 37: if (p >= sieveEnd) { prime.setWheelIndex(37); break; } + *p &= BIT7; p += sievingPrime * 4 + 3; + case 38: if (p >= sieveEnd) { prime.setWheelIndex(38); break; } + *p &= BIT3; p += sievingPrime * 6 + 4; + case 39: if (p >= sieveEnd) { prime.setWheelIndex(39); break; } + *p &= BIT1; p += sievingPrime * 2 + 1; + } + break; + for (;;) // i*30 + 23 + { + case 40: for (; p < loopLimit; p += sievingPrime * 30 + 23) + { + p[sievingPrime * 0 + 0] &= BIT5; + p[sievingPrime * 6 + 5] &= BIT1; + p[sievingPrime * 10 + 8] &= BIT2; + p[sievingPrime * 12 + 9] &= BIT6; + p[sievingPrime * 16 + 12] &= BIT7; + p[sievingPrime * 18 + 14] &= BIT3; + p[sievingPrime * 22 + 17] &= BIT4; + p[sievingPrime * 28 + 22] &= BIT0; + } + if (p >= sieveEnd) { prime.setWheelIndex(40); break; } + *p &= BIT5; p += sievingPrime * 6 + 5; + case 41: if (p >= sieveEnd) { prime.setWheelIndex(41); break; } + *p &= BIT1; p += sievingPrime * 4 + 3; + case 42: if (p >= sieveEnd) { prime.setWheelIndex(42); break; } + *p &= BIT2; p += sievingPrime * 2 + 1; + case 43: if (p >= sieveEnd) { prime.setWheelIndex(43); break; } + *p &= BIT6; p += sievingPrime * 4 + 3; + case 44: if (p >= sieveEnd) { prime.setWheelIndex(44); break; } + *p &= BIT7; p += sievingPrime * 2 + 2; + case 45: if (p >= sieveEnd) { prime.setWheelIndex(45); break; } + *p &= BIT3; p += sievingPrime * 4 + 3; + case 46: if (p >= sieveEnd) { prime.setWheelIndex(46); break; } + *p &= BIT4; p += sievingPrime * 6 + 5; + case 47: if (p >= sieveEnd) { prime.setWheelIndex(47); break; } + *p &= BIT0; p += sievingPrime * 2 + 1; + } + break; + for (;;) // i*30 + 29 + { + case 48: for (; p < loopLimit; p += sievingPrime * 30 + 29) + { + p[sievingPrime * 0 + 0] &= BIT6; + p[sievingPrime * 6 + 6] &= BIT5; + p[sievingPrime * 10 + 10] &= BIT4; + p[sievingPrime * 12 + 12] &= BIT3; + p[sievingPrime * 16 + 16] &= BIT2; + p[sievingPrime * 18 + 18] &= BIT1; + p[sievingPrime * 22 + 22] &= BIT0; + p[sievingPrime * 28 + 27] &= BIT7; + } + if (p >= sieveEnd) { prime.setWheelIndex(48); break; } + *p &= BIT6; p += sievingPrime * 6 + 6; + case 49: if (p >= sieveEnd) { prime.setWheelIndex(49); break; } + *p &= BIT5; p += sievingPrime * 4 + 4; + case 50: if (p >= sieveEnd) { prime.setWheelIndex(50); break; } + *p &= BIT4; p += sievingPrime * 2 + 2; + case 51: if (p >= sieveEnd) { prime.setWheelIndex(51); break; } + *p &= BIT3; p += sievingPrime * 4 + 4; + case 52: if (p >= sieveEnd) { prime.setWheelIndex(52); break; } + *p &= BIT2; p += sievingPrime * 2 + 2; + case 53: if (p >= sieveEnd) { prime.setWheelIndex(53); break; } + *p &= BIT1; p += sievingPrime * 4 + 4; + case 54: if (p >= sieveEnd) { prime.setWheelIndex(54); break; } + *p &= BIT0; p += sievingPrime * 6 + 5; + case 55: if (p >= sieveEnd) { prime.setWheelIndex(55); break; } + *p &= BIT7; p += sievingPrime * 2 + 2; + } + break; + for (;;) // i*30 + 31 + { + case 56: for (; p < loopLimit; p += sievingPrime * 30 + 1) + { + p[sievingPrime * 0 + 0] &= BIT7; + p[sievingPrime * 6 + 1] &= BIT0; + p[sievingPrime * 10 + 1] &= BIT1; + p[sievingPrime * 12 + 1] &= BIT2; + p[sievingPrime * 16 + 1] &= BIT3; + p[sievingPrime * 18 + 1] &= BIT4; + p[sievingPrime * 22 + 1] &= BIT5; + p[sievingPrime * 28 + 1] &= BIT6; + } + if (p >= sieveEnd) { prime.setWheelIndex(56); break; } + *p &= BIT7; p += sievingPrime * 6 + 1; + case 57: if (p >= sieveEnd) { prime.setWheelIndex(57); break; } + *p &= BIT0; p += sievingPrime * 4 + 0; + case 58: if (p >= sieveEnd) { prime.setWheelIndex(58); break; } + *p &= BIT1; p += sievingPrime * 2 + 0; + case 59: if (p >= sieveEnd) { prime.setWheelIndex(59); break; } + *p &= BIT2; p += sievingPrime * 4 + 0; + case 60: if (p >= sieveEnd) { prime.setWheelIndex(60); break; } + *p &= BIT3; p += sievingPrime * 2 + 0; + case 61: if (p >= sieveEnd) { prime.setWheelIndex(61); break; } + *p &= BIT4; p += sievingPrime * 4 + 0; + case 62: if (p >= sieveEnd) { prime.setWheelIndex(62); break; } + *p &= BIT5; p += sievingPrime * 6 + 0; + case 63: if (p >= sieveEnd) { prime.setWheelIndex(63); break; } + *p &= BIT6; p += sievingPrime * 2 + 0; + } + break; + } + // set multipleIndex for next segment + prime.setMultipleIndex((uint64_t) (p - sieveEnd)); + } +} + +} // namespace diff -Nru primesieve-6.3+ds/src/gui/primesieve.pro primesieve-7.0+ds/src/gui/primesieve.pro --- primesieve-6.3+ds/src/gui/primesieve.pro 2017-11-18 12:38:21.000000000 +0000 +++ primesieve-7.0+ds/src/gui/primesieve.pro 2018-06-08 08:51:41.000000000 +0000 @@ -28,33 +28,35 @@ src/PrimeSieveProcess.cpp HEADERS += \ - src/calculator.hpp \ + ../../include/primesieve/calculator.hpp \ src/PrimeSieveGUI.hpp \ src/PrimeSieveGUI_const.hpp \ src/PrimeSieveProcess.hpp # --------------------------------------------------------- -# Sieve of Eratosthenes sources (src/primesieve) +# Sieve of Eratosthenes source code # --------------------------------------------------------- INCLUDEPATH += ../../include SOURCES += \ - ../primesieve/api.cpp \ - ../primesieve/CpuInfo.cpp \ - ../primesieve/EratBig.cpp \ - ../primesieve/EratMedium.cpp \ - ../primesieve/EratSmall.cpp \ - ../primesieve/iterator.cpp \ - ../primesieve/nthPrime.cpp \ - ../primesieve/ParallelPrimeSieve.cpp \ - ../primesieve/popcount.cpp \ - ../primesieve/PreSieve.cpp \ - ../primesieve/PrimeGenerator.cpp \ - ../primesieve/SievingPrimes.cpp \ - ../primesieve/PrimeSieve.cpp \ - ../primesieve/SieveOfEratosthenes.cpp \ - ../primesieve/Wheel.cpp + ../api.cpp \ + ../CpuInfo.cpp \ + ../EratBig.cpp \ + ../EratMedium.cpp \ + ../EratSmall.cpp \ + ../iterator.cpp \ + ../IteratorHelper.cpp \ + ../PrimeGenerator.cpp \ + ../nthPrime.cpp \ + ../ParallelSieve.cpp \ + ../popcount.cpp \ + ../PreSieve.cpp \ + ../PrintPrimes.cpp \ + ../SievingPrimes.cpp \ + ../PrimeSieve.cpp \ + ../Erat.cpp \ + ../Wheel.cpp # --------------------------------------------------------- # primesieve icon file @@ -76,11 +78,11 @@ } *g++* { - QMAKE_CXXFLAGS += -std=c++11 -Wno-implicit-fallthrough + QMAKE_CXXFLAGS += -std=c++14 -Wno-implicit-fallthrough } *clang* { - QMAKE_CXXFLAGS += -std=c++11 -Wno-implicit-fallthrough + QMAKE_CXXFLAGS += -std=c++14 -Wno-implicit-fallthrough } *icc* { diff -Nru primesieve-6.3+ds/src/gui/README primesieve-7.0+ds/src/gui/README --- primesieve-6.3+ds/src/gui/README 2017-11-18 12:38:21.000000000 +0000 +++ primesieve-7.0+ds/src/gui/README 2018-06-08 08:51:41.000000000 +0000 @@ -28,12 +28,12 @@ * src/PrimeSieveProcess.cpp & .h Class that is used for prime sieving. PrimeSieveProcess launches - a ParallelPrimeSieve instance in a new process, this approach + a ParallelSieve instance in a new process, this approach allows to easily cancel sieving by killing the process. The inter-process communication between the GUI process - (PrimeSieveGUI) and the ParallelPrimeSieve instance is realised + (PrimeSieveGUI) and the ParallelSieve instance is realised via shared memory. * src/main.cpp - Contains the ParallelPrimeSieve code launched by PrimeSieveProcess + Contains the ParallelSieve code launched by PrimeSieveProcess objects. diff -Nru primesieve-6.3+ds/src/gui/src/calculator.hpp primesieve-7.0+ds/src/gui/src/calculator.hpp --- primesieve-6.3+ds/src/gui/src/calculator.hpp 2017-11-18 12:38:21.000000000 +0000 +++ primesieve-7.0+ds/src/gui/src/calculator.hpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,458 +0,0 @@ -/// -/// @file calculator.hpp -/// @brief calculator::eval(const std::string&) evaluates an integer -/// arithmetic expression and returns the result. If an error -/// occurs a calculator::error exception is thrown. -/// -/// @author Kim Walisch, -/// @copyright Copyright (C) 2017 Kim Walisch -/// @license BSD 2-Clause, http://opensource.org/licenses/BSD-2-Clause -/// @version 1.1 patched: `^' is raise to power instead of XOR. -/// -/// == Supported operators == -/// -/// OPERATOR NAME ASSOCIATIVITY PRECEDENCE -/// -/// | Bitwise Inclusive OR Left 4 -/// & Bitwise AND Left 6 -/// << Shift Left Left 9 -/// >> Shift Right Left 9 -/// + Addition Left 10 -/// - Subtraction Left 10 -/// * Multiplication Left 20 -/// / Division Left 20 -/// % Modulo Left 20 -/// ^, ** Raise to power Right 30 -/// e, E Scientific notation Right 40 -/// ~ Unary complement Left 99 -/// -/// The operator precedence has been set according to (uses the C and -/// C++ operator precedence): http://en.wikipedia.org/wiki/Order_of_operations -/// Operators with higher precedence are evaluated before operators -/// with relatively lower precedence. Unary operators are set to have -/// the highest precedence, this is not strictly correct for the power -/// operator e.g. "-3**2" = 9 but a lot of software tools (Bash shell, -/// Microsoft Excel, GNU bc, ...) use the same convention. -/// -/// == Examples of valid expressions == -/// -/// "65536 >> 15" = 2 -/// "2**16" = 65536 -/// "(0 + 0xDf234 - 1000)*3/2%999" = 828 -/// "-(2**2**2**2)" = -65536 -/// "(0 + ~(0xDF234 & 1000) *3) /-2" = 817 -/// "(2**16) + (1 << 16) >> 0X5" = 4096 -/// "5*-(2**(9+7))/3+5*(1 & 0xFf123)" = -109221 -/// -/// == About the algorithm used == -/// -/// calculator::eval(std::string&) relies on the ExpressionParser -/// class which is a simple C++ operator precedence parser with infix -/// notation for integer arithmetic expressions. -/// ExpressionParser has its roots in a JavaScript parser published -/// at: http://stackoverflow.com/questions/28256/equation-expression-parser-with-precedence/114961#114961 -/// The same author has also published an article about his operator -/// precedence algorithm at PerlMonks: -/// http://www.perlmonks.org/?node_id=554516 -/// - -#ifndef CALCULATOR_HPP -#define CALCULATOR_HPP - -#include -#include -#include -#include -#include -#include - -namespace calculator -{ - -/// calculator::eval() throws a calculator::error if it fails -/// to evaluate the expression string. -/// -class error : public std::runtime_error -{ -public: - error(const std::string& expr, const std::string& message) - : std::runtime_error(message), - expr_(expr) - { } -#if __cplusplus >= 201103L - ~error() { } -#else - ~error() throw() { } -#endif - std::string expression() const - { - return expr_; - } -private: - std::string expr_; -}; - -template -class ExpressionParser -{ -public: - /// Evaluate an integer arithmetic expression and return its result. - /// @throw error if parsing fails. - /// - T eval(const std::string& expr) - { - T result = 0; - index_ = 0; - expr_ = expr; - try - { - result = parseExpr(); - if (!isEnd()) - unexpected(); - } - catch (const calculator::error&) - { - while(!stack_.empty()) - stack_.pop(); - throw; - } - return result; - } - - /// Get the integer value of a character. - T eval(char c) - { - std::string expr(1, c); - return eval(expr); - } - -private: - enum - { - OPERATOR_NULL, - OPERATOR_BITWISE_OR, /// | - OPERATOR_BITWISE_XOR, /// ^ - OPERATOR_BITWISE_AND, /// & - OPERATOR_BITWISE_SHL, /// << - OPERATOR_BITWISE_SHR, /// >> - OPERATOR_ADDITION, /// + - OPERATOR_SUBTRACTION, /// - - OPERATOR_MULTIPLICATION, /// * - OPERATOR_DIVISION, /// / - OPERATOR_MODULO, /// % - OPERATOR_POWER, /// ** - OPERATOR_EXPONENT /// e, E - }; - - struct Operator - { - /// Operator, one of the OPERATOR_* enum definitions - int op; - int precedence; - /// 'L' = left or 'R' = right - int associativity; - Operator(int opr, int prec, int assoc) : - op(opr), - precedence(prec), - associativity(assoc) - { } - }; - - struct OperatorValue - { - Operator op; - T value; - OperatorValue(const Operator& opr, T val) : - op(opr), - value(val) - { } - int getPrecedence() const - { - return op.precedence; - } - bool isNull() const - { - return op.op == OPERATOR_NULL; - } - }; - - /// Expression string - std::string expr_; - /// Current expression index, incremented whilst parsing - std::size_t index_; - /// The current operator and its left value - /// are pushed onto the stack if the operator on - /// top of the stack has lower precedence. - std::stack stack_; - - /// Exponentiation by squaring, x^n. - static T pow(T x, T n) - { - T res = 1; - while (n != 0) - { - if (n % 2 != 0) - { - res *= x; - n -= 1; - } - x *= x; - n /= 2; - } - return res; - } - - T checkZero(T value) const - { - if (value == 0) - { - std::string divOperators("/%"); - std::size_t division = expr_.find_last_of(divOperators, index_ - 2); - std::ostringstream msg; - msg << "Parser error: division by 0"; - if (division != std::string::npos) - msg << " (error token is \"" - << expr_.substr(division, expr_.size() - division) - << "\")"; - throw calculator::error(expr_, msg.str()); - } - return value; - } - - T calculate(T v1, T v2, const Operator& op) const - { - switch (op.op) - { - case OPERATOR_BITWISE_OR: return v1 | v2; - case OPERATOR_BITWISE_XOR: return v1 ^ v2; - case OPERATOR_BITWISE_AND: return v1 & v2; - case OPERATOR_BITWISE_SHL: return v1 << v2; - case OPERATOR_BITWISE_SHR: return v1 >> v2; - case OPERATOR_ADDITION: return v1 + v2; - case OPERATOR_SUBTRACTION: return v1 - v2; - case OPERATOR_MULTIPLICATION: return v1 * v2; - case OPERATOR_DIVISION: return v1 / checkZero(v2); - case OPERATOR_MODULO: return v1 % checkZero(v2); - case OPERATOR_POWER: return pow(v1, v2); - case OPERATOR_EXPONENT: return v1 * pow(10, v2); - default: return 0; - } - } - - bool isEnd() const - { - return index_ >= expr_.size(); - } - - /// Returns the character at the current expression index or - /// 0 if the end of the expression is reached. - /// - char getCharacter() const - { - if (!isEnd()) - return expr_[index_]; - return 0; - } - - /// Parse str at the current expression index. - /// @throw error if parsing fails. - /// - void expect(const std::string& str) - { - if (expr_.compare(index_, str.size(), str) != 0) - unexpected(); - index_ += str.size(); - } - - void unexpected() const - { - std::ostringstream msg; - msg << "Syntax error: unexpected token \"" - << expr_.substr(index_, expr_.size() - index_) - << "\" at index " - << index_; - throw calculator::error(expr_, msg.str()); - } - - /// Eat all white space characters at the - /// current expression index. - /// - void eatSpaces() - { - while (std::isspace(getCharacter()) != 0) - index_++; - } - - /// Parse a binary operator at the current expression index. - /// @return Operator with precedence and associativity. - /// - Operator parseOp() - { - eatSpaces(); - switch (getCharacter()) - { - case '|': index_++; return Operator(OPERATOR_BITWISE_OR, 4, 'L'); - case '&': index_++; return Operator(OPERATOR_BITWISE_AND, 6, 'L'); - case '<': expect("<<"); return Operator(OPERATOR_BITWISE_SHL, 9, 'L'); - case '>': expect(">>"); return Operator(OPERATOR_BITWISE_SHR, 9, 'L'); - case '+': index_++; return Operator(OPERATOR_ADDITION, 10, 'L'); - case '-': index_++; return Operator(OPERATOR_SUBTRACTION, 10, 'L'); - case '/': index_++; return Operator(OPERATOR_DIVISION, 20, 'L'); - case '%': index_++; return Operator(OPERATOR_MODULO, 20, 'L'); - case '*': index_++; if (getCharacter() != '*') - return Operator(OPERATOR_MULTIPLICATION, 20, 'L'); - index_++; return Operator(OPERATOR_POWER, 30, 'R'); - case '^': index_++; return Operator(OPERATOR_POWER, 30, 'R'); - case 'e': index_++; return Operator(OPERATOR_EXPONENT, 40, 'R'); - case 'E': index_++; return Operator(OPERATOR_EXPONENT, 40, 'R'); - default : return Operator(OPERATOR_NULL, 0, 'L'); - } - } - - static T toInteger(char c) - { - if (c >= '0' && c <= '9') return c -'0'; - if (c >= 'a' && c <= 'f') return c -'a' + 0xa; - if (c >= 'A' && c <= 'F') return c -'A' + 0xa; - T noDigit = 0xf + 1; - return noDigit; - } - - T getInteger() const - { - return toInteger(getCharacter()); - } - - T parseDecimal() - { - T value = 0; - for (T d; (d = getInteger()) <= 9; index_++) - value = value * 10 + d; - return value; - } - - T parseHex() - { - index_ = index_ + 2; - T value = 0; - for (T h; (h = getInteger()) <= 0xf; index_++) - value = value * 0x10 + h; - return value; - } - - bool isHex() const - { - if (index_ + 2 < expr_.size()) - { - char x = expr_[index_ + 1]; - char h = expr_[index_ + 2]; - return (std::tolower(x) == 'x' && toInteger(h) <= 0xf); - } - return false; - } - - /// Parse an integer value at the current expression index. - /// The unary `+', `-' and `~' operators and opening - /// parentheses `(' cause recursion. - /// - T parseValue() - { - T val = 0; - eatSpaces(); - switch (getCharacter()) - { - case '0': if (isHex()) - val = parseHex(); - else - val = parseDecimal(); - break; - case '1': case '2': case '3': case '4': case '5': - case '6': case '7': case '8': case '9': - val = parseDecimal(); - break; - case '(': index_++; - val = parseExpr(); - eatSpaces(); - if (getCharacter() != ')') - { - if (!isEnd()) - unexpected(); - throw calculator::error(expr_, "Syntax error: `)' expected at end of expression"); - } - index_++; break; - case '~': index_++; val = ~parseValue(); break; - case '+': index_++; val = parseValue(); break; - case '-': index_++; val = parseValue() * static_cast(-1); - break; - default : if (!isEnd()) - unexpected(); - throw calculator::error(expr_, "Syntax error: value expected at end of expression"); - } - return val; - } - - /// Parse all operations of the current parenthesis - /// level and the levels above, when done - /// return the result (value). - /// - T parseExpr() - { - stack_.push(OperatorValue(Operator(OPERATOR_NULL, 0, 'L'), 0)); - // first parse value on the left - T value = parseValue(); - - while (!stack_.empty()) - { - // parse an operator (+, -, *, ...) - Operator op(parseOp()); - while (op.precedence < stack_.top().getPrecedence() || ( - op.precedence == stack_.top().getPrecedence() && - op.associativity == 'L')) - { - // end reached - if (stack_.top().isNull()) - { - stack_.pop(); - return value; - } - // do the calculation ("reduce"), producing a new value - value = calculate(stack_.top().value, value, stack_.top().op); - stack_.pop(); - } - - // store on stack_ and continue parsing ("shift") - stack_.push(OperatorValue(op, value)); - // parse value on the right - value = parseValue(); - } - return 0; - } -}; - -template -inline T eval(const std::string& expression) -{ - ExpressionParser parser; - return parser.eval(expression); -} - -template -inline T eval(char c) -{ - ExpressionParser parser; - return parser.eval(c); -} - -inline int eval(const std::string& expression) -{ - return eval(expression); -} - -inline int eval(char c) -{ - return eval(c); -} - -} // namespace calculator - -#endif diff -Nru primesieve-6.3+ds/src/gui/src/main.cpp primesieve-7.0+ds/src/gui/src/main.cpp --- primesieve-6.3+ds/src/gui/src/main.cpp 2017-11-18 12:38:21.000000000 +0000 +++ primesieve-7.0+ds/src/gui/src/main.cpp 2018-06-08 08:51:41.000000000 +0000 @@ -1,7 +1,7 @@ /* * main.cpp -- This file is part of primesieve * - * Copyright (C) 2012 Kim Walisch, + * Copyright (C) 2018 Kim Walisch, * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -18,7 +18,7 @@ */ #include "PrimeSieveGUI.hpp" -#include +#include #if QT_VERSION >= 0x050000 #include @@ -57,23 +57,23 @@ exit(EXIT_FAILURE); } // map the attached shared memory to the shm segment - primesieve::ParallelPrimeSieve::SharedMemory* shm = - static_cast(sharedMemory.data()); + primesieve::ParallelSieve::SharedMemory* shm = + static_cast(sharedMemory.data()); try { - // initialize the ParallelPrimeSieve object with + // initialize the ParallelSieve object with // values from the shared memory segment provided by // the primesieve GUI and start sieving if (!shm) throw std::runtime_error("sharedMemory.data() must not be NULL"); - primesieve::ParallelPrimeSieve pps; - pps.init(*shm); - pps.sieve(); + primesieve::ParallelSieve ps; + ps.init(*shm); + ps.sieve(); } catch (std::exception& e) { sharedMemory.detach(); - std::cerr << "ParallelPrimeSieve error: " << e.what() << std::endl; + std::cerr << "ParallelSieve error: " << e.what() << std::endl; exit(EXIT_FAILURE); } sharedMemory.detach(); diff -Nru primesieve-6.3+ds/src/gui/src/PrimeSieveGUI_const.hpp primesieve-7.0+ds/src/gui/src/PrimeSieveGUI_const.hpp --- primesieve-6.3+ds/src/gui/src/PrimeSieveGUI_const.hpp 2017-11-18 12:38:21.000000000 +0000 +++ primesieve-7.0+ds/src/gui/src/PrimeSieveGUI_const.hpp 2018-06-08 08:51:41.000000000 +0000 @@ -1,7 +1,7 @@ /* * PrimeSieveGUI_const.hpp -- This file is part of primesieve * - * Copyright (C) 2017 Kim Walisch, + * Copyright (C) 2018 Kim Walisch, * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -34,9 +34,9 @@ #include const QString APPLICATION_NAME("primesieve"); -const QString APPLICATION_HOMEPAGE("http://primesieve.org"); +const QString APPLICATION_HOMEPAGE("https://primesieve.org"); const QString APPLICATION_ABOUT( - "

Copyright © 2017 Kim Walisch

" + "

Copyright © 2018 Kim Walisch

" "

primesieve generates prime numbers and prime k-tuplets using a highly " "optimized implementation of the sieve of Eratosthenes. By the date " "of release this is the fastest publicly available prime generation software." diff -Nru primesieve-6.3+ds/src/gui/src/PrimeSieveGUI.cpp primesieve-7.0+ds/src/gui/src/PrimeSieveGUI.cpp --- primesieve-6.3+ds/src/gui/src/PrimeSieveGUI.cpp 2017-11-18 12:38:21.000000000 +0000 +++ primesieve-7.0+ds/src/gui/src/PrimeSieveGUI.cpp 2018-06-08 08:51:41.000000000 +0000 @@ -1,7 +1,7 @@ /* * PrimeSieveGUI.cpp -- This file is part of primesieve * - * Copyright (C) 2017 Kim Walisch, + * Copyright (C) 2018 Kim Walisch, * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -20,11 +20,11 @@ #include "PrimeSieveGUI.hpp" #include "ui_PrimeSieveGUI.h" #include "PrimeSieveProcess.hpp" -#include "calculator.hpp" #include +#include #include -#include +#include #include #if QT_VERSION >= 0x050000 @@ -105,7 +105,7 @@ int sieveSize = get_sieve_size(); this->setTo(ui->sieveSizeComboBox, QString::number(sieveSize) + " KB"); - maxThreads_ = ParallelPrimeSieve::getMaxThreads(); + maxThreads_ = ParallelSieve::getMaxThreads(); std::set threads; threads.insert(maxThreads_); @@ -206,10 +206,10 @@ try { quint64 lowerBound = this->getNumber(ui->lowerBoundLineEdit->text()); quint64 upperBound = this->getNumber(ui->upperBoundLineEdit->text()); - ParallelPrimeSieve pps; - pps.setStart(lowerBound); - pps.setStop(upperBound); - int idealNumThreads = pps.idealNumThreads(); + ParallelSieve ps; + ps.setStart(lowerBound); + ps.setStop(upperBound); + int idealNumThreads = ps.idealNumThreads(); if (idealNumThreads < maxThreads_) { // floor to the next power of 2 value int p = 1; diff -Nru primesieve-6.3+ds/src/gui/src/PrimeSieveGUI.hpp primesieve-7.0+ds/src/gui/src/PrimeSieveGUI.hpp --- primesieve-6.3+ds/src/gui/src/PrimeSieveGUI.hpp 2017-11-18 12:38:21.000000000 +0000 +++ primesieve-7.0+ds/src/gui/src/PrimeSieveGUI.hpp 2018-06-08 08:51:41.000000000 +0000 @@ -1,7 +1,7 @@ /* * PrimeSieveGUI.hpp -- This file is part of primesieve * - * Copyright (C) 2012 Kim Walisch, + * Copyright (C) 2018 Kim Walisch, * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -21,7 +21,7 @@ #define PRIMESIEVEGUI_HPP #include "PrimeSieveGUI_const.hpp" -#include +#include #if QT_VERSION >= 0x050000 #include @@ -84,12 +84,12 @@ Ui::PrimeSieveGUI* ui; enum { - COUNT_PRIMES = primesieve::ParallelPrimeSieve::COUNT_PRIMES, - COUNT_KTUPLETS = primesieve::ParallelPrimeSieve::COUNT_SEXTUPLETS * 2 - primesieve::ParallelPrimeSieve::COUNT_TWINS, - COUNT_FLAGS = primesieve::ParallelPrimeSieve::COUNT_SEXTUPLETS * 2 - primesieve::ParallelPrimeSieve::COUNT_PRIMES, - PRINT_FLAGS = primesieve::ParallelPrimeSieve::PRINT_SEXTUPLETS * 2 - primesieve::ParallelPrimeSieve::PRINT_PRIMES, - PRINT_PRIMES = primesieve::ParallelPrimeSieve::PRINT_PRIMES, - CALCULATE_STATUS = primesieve::ParallelPrimeSieve::CALCULATE_STATUS + COUNT_PRIMES = primesieve::COUNT_PRIMES, + COUNT_KTUPLETS = primesieve::COUNT_SEXTUPLETS * 2 - primesieve::COUNT_TWINS, + COUNT_FLAGS = primesieve::COUNT_SEXTUPLETS * 2 - primesieve::COUNT_PRIMES, + PRINT_FLAGS = primesieve::PRINT_SEXTUPLETS * 2 - primesieve::PRINT_PRIMES, + PRINT_PRIMES = primesieve::PRINT_PRIMES, + CALCULATE_STATUS = primesieve::CALCULATE_STATUS }; void initGUI(); diff -Nru primesieve-6.3+ds/src/gui/src/PrimeSieveGUI_menu.cpp primesieve-7.0+ds/src/gui/src/PrimeSieveGUI_menu.cpp --- primesieve-6.3+ds/src/gui/src/PrimeSieveGUI_menu.cpp 2017-11-18 12:38:21.000000000 +0000 +++ primesieve-7.0+ds/src/gui/src/PrimeSieveGUI_menu.cpp 2018-06-08 08:51:41.000000000 +0000 @@ -21,7 +21,7 @@ #include "ui_PrimeSieveGUI.h" #include -#include +#include #if QT_VERSION >= 0x050000 #include diff -Nru primesieve-6.3+ds/src/gui/src/PrimeSieveProcess.cpp primesieve-7.0+ds/src/gui/src/PrimeSieveProcess.cpp --- primesieve-6.3+ds/src/gui/src/PrimeSieveProcess.cpp 2017-11-18 12:38:21.000000000 +0000 +++ primesieve-7.0+ds/src/gui/src/PrimeSieveProcess.cpp 2018-06-08 08:51:41.000000000 +0000 @@ -18,7 +18,7 @@ */ #include "PrimeSieveProcess.hpp" -#include +#include #include #include @@ -60,7 +60,7 @@ /** * Create a shared memory segment for communication with the - * ParallelPrimeSieve process. + * ParallelSieve process. */ void PrimeSieveProcess::createSharedMemory() { // attach the shared memory @@ -70,11 +70,11 @@ "Interprocess communication error, could not allocate shared memory."); } // map the attached shared memory to the shm_ segment - shm_ = static_cast(sharedMemory_.data()); + shm_ = static_cast(sharedMemory_.data()); } /** - * Start a new ParallelPrimeSieve process that sieves + * Start a new ParallelSieve process that sieves * the primes within [start, stop]. */ void PrimeSieveProcess::start(quint64 start, quint64 stop, @@ -95,7 +95,7 @@ // process arguments, see main.cpp QStringList args; args << "PrimeSieveProcess" << sharedMemory_.key(); - /// start a new ParallelPrimeSieve process + /// start a new ParallelSieve process /// @see main.cpp QProcess::start(path, args, QIODevice::ReadOnly); } diff -Nru primesieve-6.3+ds/src/gui/src/PrimeSieveProcess.hpp primesieve-7.0+ds/src/gui/src/PrimeSieveProcess.hpp --- primesieve-6.3+ds/src/gui/src/PrimeSieveProcess.hpp 2017-11-18 12:38:21.000000000 +0000 +++ primesieve-7.0+ds/src/gui/src/PrimeSieveProcess.hpp 2018-06-08 08:51:41.000000000 +0000 @@ -20,7 +20,7 @@ #ifndef PRIMESIEVEPROCESS_HPP #define PRIMESIEVEPROCESS_HPP -#include +#include #include #include @@ -31,7 +31,7 @@ /** * QProcess class used for prime sieving, using a separate process * for sieving allows to easily cancel a multi-threaded - * ParallelPrimeSieve instance. + * ParallelSieve instance. */ class PrimeSieveProcess : public QProcess { public: @@ -44,11 +44,11 @@ double getSeconds() const; private: /// Shared memory for interprocess communication between the - /// Qt GUI process and the ParallelPrimeSieve process. + /// Qt GUI process and the ParallelSieve process. QSharedMemory sharedMemory_; /// Contains the settings (start, stop, sieveSize, ...) /// for sieving, will be mapped to sharedMemory_ - primesieve::ParallelPrimeSieve::SharedMemory* shm_; + primesieve::ParallelSieve::SharedMemory* shm_; void createSharedMemory(); int getProcessId(); }; diff -Nru primesieve-6.3+ds/src/iterator-c.cpp primesieve-7.0+ds/src/iterator-c.cpp --- primesieve-6.3+ds/src/iterator-c.cpp 1970-01-01 00:00:00.000000000 +0000 +++ primesieve-7.0+ds/src/iterator-c.cpp 2018-06-08 08:51:41.000000000 +0000 @@ -0,0 +1,163 @@ +/// +/// @file iterator-c.cpp +/// @brief C port of primesieve::iterator. +/// +/// Copyright (C) 2018 Kim Walisch, +/// +/// This file is distributed under the BSD License. See the COPYING +/// file in the top level directory. +/// + +#include +#include +#include +#include + +#include +#include +#include +#include + +using namespace std; +using namespace primesieve; + +namespace { + +PrimeGenerator* getPrimeGenerator(primesieve_iterator* it) +{ + // primeGenerator is a pimpl + return (PrimeGenerator*) it->primeGenerator; +} + +void clearPrimeGenerator(primesieve_iterator* it) +{ + delete getPrimeGenerator(it); + it->primeGenerator = nullptr; +} + +vector& getPrimes(primesieve_iterator* it) +{ + using T = vector; + T* primes = (T*) it->vector; + return *primes; +} + +} // namespace + +/// C constructor +void primesieve_init(primesieve_iterator* it) +{ + it->start = 0; + it->stop = 0; + it->stop_hint = get_max_stop(); + it->i = 0; + it->last_idx = 0; + it->dist = PrimeGenerator::maxCachedPrime(); + it->vector = new vector; + it->primeGenerator = nullptr; + it->is_error = false; +} + +void primesieve_skipto(primesieve_iterator* it, + uint64_t start, + uint64_t stop_hint) +{ + it->start = start; + it->stop = start; + it->stop_hint = stop_hint; + it->i = 0; + it->last_idx = 0; + it->dist = PrimeGenerator::maxCachedPrime(); + auto& primes = getPrimes(it); + primes.clear(); + clearPrimeGenerator(it); +} + +/// C destructor +void primesieve_free_iterator(primesieve_iterator* it) +{ + if (it) + { + clearPrimeGenerator(it); + auto* primes = &getPrimes(it); + delete primes; + } +} + +void primesieve_generate_next_primes(primesieve_iterator* it) +{ + auto& primes = getPrimes(it); + auto primeGenerator = getPrimeGenerator(it); + + try + { + while (true) + { + if (!it->primeGenerator) + { + IteratorHelper::next(&it->start, &it->stop, it->stop_hint, &it->dist); + it->primeGenerator = new PrimeGenerator(it->start, it->stop); + primeGenerator = getPrimeGenerator(it); + primes.resize(64); + it->primes = &primes[0]; + } + + for (it->last_idx = 0; !it->last_idx;) + primeGenerator->fill(primes, &it->last_idx); + + if (primeGenerator->finished()) + clearPrimeGenerator(it); + else + break; + } + } + catch (exception&) + { + clearPrimeGenerator(it); + primes.resize(1); + primes[0] = PRIMESIEVE_ERROR; + it->last_idx = 1; + it->is_error = true; + errno = EDOM; + } + + it->i = 0; + it->last_idx--; +} + +void primesieve_generate_prev_primes(primesieve_iterator* it) +{ + auto& primes = getPrimes(it); + + try + { + if (it->primeGenerator) + it->start = primes.front(); + + primes.clear(); + clearPrimeGenerator(it); + + while (primes.empty()) + { + IteratorHelper::prev(&it->start, &it->stop, it->stop_hint, &it->dist); + it->primeGenerator = new PrimeGenerator(it->start, it->stop); + auto primeGenerator = getPrimeGenerator(it); + if (it->start <= 2) + primes.push_back(0); + primeGenerator->fill(primes); + clearPrimeGenerator(it); + } + } + catch (exception&) + { + clearPrimeGenerator(it); + primes.resize(1); + primes[0] = PRIMESIEVE_ERROR; + it->is_error = true; + errno = EDOM; + } + + it->primes = &primes[0]; + it->last_idx = primes.size() - 1; + it->i = it->last_idx; +} diff -Nru primesieve-6.3+ds/src/iterator.cpp primesieve-7.0+ds/src/iterator.cpp --- primesieve-6.3+ds/src/iterator.cpp 1970-01-01 00:00:00.000000000 +0000 +++ primesieve-7.0+ds/src/iterator.cpp 2018-06-08 08:51:41.000000000 +0000 @@ -0,0 +1,99 @@ +/// +/// @file iterator.cpp +/// +/// Copyright (C) 2018 Kim Walisch, +/// +/// This file is distributed under the BSD License. See the COPYING +/// file in the top level directory. +/// + +#include +#include +#include + +#include +#include +#include + +namespace { + +template +void clear(std::unique_ptr& ptr) +{ + ptr.reset(nullptr); +} + +} // namespace + +namespace primesieve { + +iterator::~iterator() +{ } + +iterator::iterator(uint64_t start, + uint64_t stop_hint) +{ + skipto(start, stop_hint); +} + +void iterator::skipto(uint64_t start, + uint64_t stop_hint) +{ + start_ = start; + stop_ = start; + stop_hint_ = stop_hint; + i_ = 0; + last_idx_ = 0; + dist_ = PrimeGenerator::maxCachedPrime(); + clear(primeGenerator_); + primes_.clear(); +} + +void iterator::generate_next_primes() +{ + while (true) + { + if (!primeGenerator_) + { + IteratorHelper::next(&start_, &stop_, stop_hint_, &dist_); + auto p = new PrimeGenerator(start_, stop_); + primeGenerator_.reset(p); + primes_.resize(64); + } + + for (last_idx_ = 0; !last_idx_;) + primeGenerator_->fill(primes_, &last_idx_); + + if (primeGenerator_->finished()) + clear(primeGenerator_); + else + break; + } + + i_ = 0; + last_idx_--; +} + +void iterator::generate_prev_primes() +{ + if (primeGenerator_) + start_ = primes_.front(); + + primes_.clear(); + + while (primes_.empty()) + { + IteratorHelper::prev(&start_, &stop_, stop_hint_, &dist_); + if (start_ <= 2) + primes_.push_back(0); + auto p = new PrimeGenerator(start_, stop_); + primeGenerator_.reset(p); + primeGenerator_->fill(primes_); + clear(primeGenerator_); + } + + last_idx_ = primes_.size() - 1; + i_ = last_idx_; +} + +} // namespace diff -Nru primesieve-6.3+ds/src/IteratorHelper.cpp primesieve-7.0+ds/src/IteratorHelper.cpp --- primesieve-6.3+ds/src/IteratorHelper.cpp 1970-01-01 00:00:00.000000000 +0000 +++ primesieve-7.0+ds/src/IteratorHelper.cpp 2018-06-08 08:51:41.000000000 +0000 @@ -0,0 +1,115 @@ +/// +/// @file IteratorHelper.cpp +/// Functions used to calculate the next start and stop +/// numbers for primesieve::iterator. +/// +/// Copyright (C) 2018 Kim Walisch, +/// +/// This file is distributed under the BSD License. See the COPYING +/// file in the top level directory. +/// + +#include +#include +#include + +#include +#include +#include +#include + +using namespace std; +using namespace primesieve; + +namespace { + +uint64_t getNextDist(uint64_t n, uint64_t dist) +{ + double x = (double) n; + x = max(x, 16.0); + x = sqrt(x) / log(log(x)); + + uint64_t minDist = (uint64_t) x; + uint64_t limit = numeric_limits::max() / 4; + dist = max(dist, minDist); + + if (dist < limit) + dist *= 4; + + return dist; +} + +uint64_t getPrevDist(uint64_t n, uint64_t* dist) +{ + double x = (double) n; + x = max(x, 10.0); + + double minDist = config::MIN_CACHE_ITERATOR; + double maxDist = config::MAX_CACHE_ITERATOR; + double logx = log(x); + + minDist *= logx; + maxDist *= logx; + + minDist /= sizeof(uint64_t); + maxDist /= sizeof(uint64_t); + + if (*dist < minDist) + { + minDist = (double) *dist; + *dist *= 4; + } + + double defaultDist = sqrt(x) * 2; + double newDist = max(minDist, defaultDist); + newDist = min(newDist, maxDist); + + return (uint64_t) newDist; +} + +bool useStopHint(uint64_t start, + uint64_t stopHint) +{ + return stopHint >= start && + stopHint < numeric_limits::max(); +} + +bool useStopHint(uint64_t start, + uint64_t stop, + uint64_t stopHint) +{ + return stopHint >= start && + stopHint <= stop; +} + +} // namespace + +namespace primesieve { + +void IteratorHelper::next(uint64_t* start, + uint64_t* stop, + uint64_t stopHint, + uint64_t* dist) +{ + *start = checkedAdd(*stop, 1); + *dist = getNextDist(*start, *dist); + *stop = checkedAdd(*start, *dist); + + if (useStopHint(*start, stopHint)) + *stop = checkedAdd(stopHint, maxPrimeGap(stopHint)); +} + +void IteratorHelper::prev(uint64_t* start, + uint64_t* stop, + uint64_t stopHint, + uint64_t* dist) +{ + *stop = checkedSub(*start, 1); + uint64_t prevDist = getPrevDist(*stop, dist); + *start = checkedSub(*stop, prevDist); + + if (useStopHint(*start, *stop, stopHint)) + *start = checkedSub(stopHint, maxPrimeGap(stopHint)); +} + +} // namespace diff -Nru primesieve-6.3+ds/src/nthPrime.cpp primesieve-7.0+ds/src/nthPrime.cpp --- primesieve-6.3+ds/src/nthPrime.cpp 1970-01-01 00:00:00.000000000 +0000 +++ primesieve-7.0+ds/src/nthPrime.cpp 2018-06-08 08:51:41.000000000 +0000 @@ -0,0 +1,174 @@ +/// +/// @file nthPrime.cpp +/// +/// Copyright (C) 2018 Kim Walisch, +/// +/// This file is distributed under the BSD License. See the COPYING +/// file in the top level directory. +/// + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +using namespace std; +using namespace primesieve; + +namespace { + +void checkLimit(uint64_t start) +{ + if (start >= get_max_stop()) + throw primesieve_error("nth prime > 2^64"); +} + +void checkLowerLimit(uint64_t stop) +{ + if (stop == 0) + throw primesieve_error("nth prime < 2 is impossible"); +} + +bool sieveBackwards(int64_t n, int64_t count, uint64_t stop) +{ + return (count >= n) && + !(count == n && stop < 2); +} + +// Prime count approximation +int64_t pix(int64_t n) +{ + double x = (double) n; + x = max(4.0, x); + double pix = x / log(x); + return (int64_t) pix; +} + +uint64_t nthPrimeDist(int64_t n, int64_t count, uint64_t start) +{ + double x = (double) (n - count); + + x = abs(x); + x = max(x, 4.0); + + // rough pi(x) approximation + double logx = log(x); + double loglogx = log(logx); + double pix = x * (logx + loglogx - 1); + + // correct start if sieving backwards to + // get more accurate approximation + if (count >= n) + { + double st = start - pix; + st = max(0.0, st); + start = (uint64_t) st; + } + + // approximate the nth prime using: + // start + n * log(start + pi(n) / loglog(n)) + double startPix = start + pix / loglogx; + startPix = max(4.0, startPix); + double logStartPix = log(startPix); + double dist = max(pix, x * logStartPix); + + // ensure start + dist <= nth prime + if (count < n) + dist -= sqrt(dist) * log(logStartPix) * 2; + // ensure start + dist >= nth prime + if (count > n) + dist += sqrt(dist) * log(logStartPix) * 2; + + // if n is very small: + // ensure start + dist >= nth prime + double primeGap = maxPrimeGap(startPix); + dist = max(dist, primeGap); + + return (uint64_t) dist; +} + +} // namespace + +namespace primesieve { + +uint64_t PrimeSieve::nthPrime(uint64_t n) +{ + return nthPrime(0, n); +} + +uint64_t PrimeSieve::nthPrime(int64_t n, uint64_t start) +{ + setStart(start); + auto t1 = chrono::system_clock::now(); + + if (n == 0) + n = 1; // like Mathematica + else if (n > 0) + start = checkedAdd(start, 1); + else if (n < 0) + start = checkedSub(start, 1); + + uint64_t stop = start; + uint64_t dist = nthPrimeDist(n, 0, start); + uint64_t nthPrimeGuess = checkedAdd(start, dist); + + int64_t count = 0; + int64_t tinyN = 100000; + tinyN = max(tinyN, pix(isqrt(nthPrimeGuess))); + + while ((n - count) > tinyN || + sieveBackwards(n, count, stop)) + { + if (count < n) + { + checkLimit(start); + dist = nthPrimeDist(n, count, start); + stop = checkedAdd(start, dist); + count += countPrimes(start, stop); + start = checkedAdd(stop, 1); + } + if (sieveBackwards(n, count, stop)) + { + checkLowerLimit(stop); + dist = nthPrimeDist(n, count, stop); + start = checkedSub(start, dist); + count -= (int64_t) countPrimes(start, stop); + stop = checkedSub(start, 1); + } + } + + if (n < 0) + count -= 1; + + // here start < nth prime, + // hence we can sieve forward the remaining + // distance and find the nth prime + assert(count < n); + + checkLimit(start); + dist = nthPrimeDist(n, count, start) * 2; + start = checkedSub(start, 1); + stop = checkedAdd(start, dist); + uint64_t prime = 0; + + for (primesieve::iterator it(start, stop); count < n; count++) + prime = it.next_prime(); + + if (~prime == 0) + throw primesieve_error("nth prime > 2^64"); + + auto t2 = chrono::system_clock::now(); + chrono::duration seconds = t2 - t1; + seconds_ = seconds.count(); + + return prime; +} + +} // namespace diff -Nru primesieve-6.3+ds/src/ParallelSieve.cpp primesieve-7.0+ds/src/ParallelSieve.cpp --- primesieve-6.3+ds/src/ParallelSieve.cpp 1970-01-01 00:00:00.000000000 +0000 +++ primesieve-7.0+ds/src/ParallelSieve.cpp 2018-06-08 08:51:41.000000000 +0000 @@ -0,0 +1,214 @@ +/// +/// @file ParallelSieve.cpp +/// @brief Multi-threaded prime sieve using std::async. +/// +/// Copyright (C) 2018 Kim Walisch, +/// +/// This file is distributed under the BSD License. See the COPYING +/// file in the top level directory. +/// + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace std; +using namespace primesieve; + +namespace { + +counts_t& operator+=(counts_t& v1, const counts_t& v2) +{ + for (size_t i = 0; i < v1.size(); i++) + v1[i] += v2[i]; + return v1; +} + +} // namespace + +namespace primesieve { + +ParallelSieve::ParallelSieve() : + shm_(nullptr), + numThreads_(getMaxThreads()) +{ } + +void ParallelSieve::init(SharedMemory& shm) +{ + setStart(shm.start); + setStop(shm.stop); + setSieveSize(shm.sieveSize); + setFlags(shm.flags); + setNumThreads(shm.threads); + shm_ = &shm; +} + +int ParallelSieve::getMaxThreads() +{ + int maxThreads = thread::hardware_concurrency(); + return max(1, maxThreads); +} + +int ParallelSieve::getNumThreads() const +{ + return numThreads_; +} + +void ParallelSieve::setNumThreads(int threads) +{ + numThreads_ = inBetween(1, threads, getMaxThreads()); +} + +/// Get an ideal number of threads for +/// the start_ and stop_ numbers +/// +int ParallelSieve::idealNumThreads() const +{ + if (start_ > stop_) + return 1; + + uint64_t threshold = isqrt(stop_) / 5; + threshold = max(threshold, config::MIN_THREAD_DISTANCE); + uint64_t threads = getDistance() / threshold; + threads = inBetween(1, threads, numThreads_); + + return (int) threads; +} + +/// Get a thread distance which ensures a good load +/// balance when using multiple threads +/// +uint64_t ParallelSieve::getThreadDistance(int threads) const +{ + assert(threads > 0); + + uint64_t balanced = isqrt(stop_) * 1000; + uint64_t unbalanced = getDistance() / threads; + uint64_t fastest = min(balanced, unbalanced); + uint64_t threadDistance = max(config::MIN_THREAD_DISTANCE, fastest); + uint64_t iters = getDistance() / threadDistance; + + if (iters < threads * 5u) + threadDistance = max(config::MIN_THREAD_DISTANCE, unbalanced); + + threadDistance += 30 - threadDistance % 30; + return threadDistance; +} + +/// Align n to modulo (30 + 2) to prevent prime k-tuplet +/// (twin primes, prime triplets) gaps +/// +uint64_t ParallelSieve::align(uint64_t n) const +{ + uint64_t n32 = checkedAdd(n, 32); + + if (n32 >= stop_) + return stop_; + + return n32 - n % 30; +} + +/// Sieve the primes and prime k-tuplets in [start_, stop_] +/// in parallel using multi-threading +/// +void ParallelSieve::sieve() +{ + reset(); + + if (start_ > stop_) + return; + + int threads = idealNumThreads(); + + if (threads == 1) + PrimeSieve::sieve(); + else + { + auto t1 = chrono::system_clock::now(); + uint64_t threadDistance = getThreadDistance(threads); + uint64_t iters = ((getDistance() - 1) / threadDistance) + 1; + threads = inBetween(1, threads, iters); + atomic i(0); + + // each thread executes 1 task + auto task = [&]() + { + PrimeSieve ps(this); + uint64_t j; + counts_t counts; + counts.fill(0); + + while ((j = i++) < iters) + { + uint64_t start = start_ + j * threadDistance; + uint64_t stop = checkedAdd(start, threadDistance); + stop = align(stop); + if (start > start_) + start = align(start) + 1; + + // sieve the range [start, stop] + ps.sieve(start, stop); + counts += ps.getCounts(); + } + + return counts; + }; + + vector> futures; + futures.reserve(threads); + + for (int t = 0; t < threads; t++) + futures.emplace_back(async(launch::async, task)); + + for (auto &f : futures) + counts_ += f.get(); + + auto t2 = chrono::system_clock::now(); + chrono::duration seconds = t2 - t1; + seconds_ = seconds.count(); + } + + if (shm_) + { + // communicate the sieving results to + // the primesieve GUI application + copy(counts_.begin(), counts_.end(), shm_->counts); + shm_->seconds = seconds_; + } +} + +/// Print status in percent to stdout +/// @processed: Sum of recently processed segments +/// @tryLock: Do not block if tryLock = true +/// +bool ParallelSieve::updateStatus(uint64_t processed, bool tryLock) +{ + unique_lock lock(lock_, defer_lock); + + if (tryLock) + lock.try_lock(); + else + lock.lock(); + + if (lock.owns_lock()) + { + PrimeSieve::updateStatus(processed); + if (shm_) + shm_->status = getStatus(); + return true; + } + + return false; +} + +} // namespace diff -Nru primesieve-6.3+ds/src/popcount.cpp primesieve-7.0+ds/src/popcount.cpp --- primesieve-6.3+ds/src/popcount.cpp 1970-01-01 00:00:00.000000000 +0000 +++ primesieve-7.0+ds/src/popcount.cpp 2018-06-08 08:51:41.000000000 +0000 @@ -0,0 +1,95 @@ +/// +/// @file popcount.cpp +/// @brief Fast algorithm to count the number of 1 bits in an +/// array using only integer operations. +/// +/// Copyright (C) 2018 Kim Walisch, +/// +/// This file is distributed under the BSD License. See the COPYING +/// file in the top level directory. +/// + +#include + +namespace { + +/// This uses fewer arithmetic operations than any other known +/// implementation on machines with fast multiplication. +/// It uses 12 arithmetic operations, one of which is a multiply. +/// https://en.wikipedia.org/wiki/Hamming_weight#Efficient_implementation +/// +uint64_t popcount64(uint64_t x) +{ + const uint64_t m1 = 0x5555555555555555ull; + const uint64_t m2 = 0x3333333333333333ull; + const uint64_t m4 = 0x0F0F0F0F0F0F0F0Full; + const uint64_t h01 = 0x0101010101010101ull; + + x -= (x >> 1) & m1; + x = (x & m2) + ((x >> 2) & m2); + x = (x + (x >> 4)) & m4; + return (x * h01) >> 56; +} + +/// Carry-save adder (CSA). +/// @see Chapter 5 in "Hacker's Delight". +/// +void CSA(uint64_t& h, uint64_t& l, uint64_t a, uint64_t b, uint64_t c) +{ + uint64_t u = a ^ b; + h = (a & b) | (u & c); + l = u ^ c; +} + +} // namespace + +namespace primesieve { + +/// Harley-Seal popcount (4th iteration). +/// The Harley-Seal popcount algorithm is one of the fastest algorithms +/// for counting 1 bits in an array using only integer operations. +/// This implementation uses only 5.69 instructions per 64-bit word. +/// @see Chapter 5 in "Hacker's Delight" 2nd edition. +/// +uint64_t popcount(const uint64_t* array, uint64_t size) +{ + uint64_t total = 0; + uint64_t ones = 0, twos = 0, fours = 0, eights = 0, sixteens = 0; + uint64_t twosA, twosB, foursA, foursB, eightsA, eightsB; + uint64_t limit = size - size % 16; + uint64_t i = 0; + + for(; i < limit; i += 16) + { + CSA(twosA, ones, ones, array[i+0], array[i+1]); + CSA(twosB, ones, ones, array[i+2], array[i+3]); + CSA(foursA, twos, twos, twosA, twosB); + CSA(twosA, ones, ones, array[i+4], array[i+5]); + CSA(twosB, ones, ones, array[i+6], array[i+7]); + CSA(foursB, twos, twos, twosA, twosB); + CSA(eightsA,fours, fours, foursA, foursB); + CSA(twosA, ones, ones, array[i+8], array[i+9]); + CSA(twosB, ones, ones, array[i+10], array[i+11]); + CSA(foursA, twos, twos, twosA, twosB); + CSA(twosA, ones, ones, array[i+12], array[i+13]); + CSA(twosB, ones, ones, array[i+14], array[i+15]); + CSA(foursB, twos, twos, twosA, twosB); + CSA(eightsB, fours, fours, foursA, foursB); + CSA(sixteens, eights, eights, eightsA, eightsB); + + total += popcount64(sixteens); + } + + total *= 16; + total += 8 * popcount64(eights); + total += 4 * popcount64(fours); + total += 2 * popcount64(twos); + total += 1 * popcount64(ones); + + for(; i < size; i++) + total += popcount64(array[i]); + + return total; +} + +} // namespace diff -Nru primesieve-6.3+ds/src/PreSieve.cpp primesieve-7.0+ds/src/PreSieve.cpp --- primesieve-6.3+ds/src/PreSieve.cpp 1970-01-01 00:00:00.000000000 +0000 +++ primesieve-7.0+ds/src/PreSieve.cpp 2018-06-08 08:51:41.000000000 +0000 @@ -0,0 +1,103 @@ +/// +/// @file PreSieve.cpp +/// @brief Pre-sieve multiples of small primes to speed up +/// the sieve of Eratosthenes. +/// +/// Copyright (C) 2018 Kim Walisch, +/// +/// This file is distributed under the BSD License. See the COPYING +/// file in the top level directory. +/// + +#include +#include +#include +#include + +#include +#include +#include +#include + +using namespace std; +using namespace primesieve; + +namespace { + +// small primes >= 7 +const array primes = { 7, 11, 13, 17, 19 }; + +// prime products of primes >= 7 +const array primeProducts = { 210, 2310, 30030, 510510, 9699690 }; + +} // namespace + +namespace primesieve { + +PreSieve::PreSieve(uint64_t start, uint64_t stop) +{ + // use a small buffer_ array if the + // sieve interval is small + uint64_t distance = stop - start; + uint64_t threshold = max(distance, isqrt(stop)) / 10; + size_t i = 0; + + for (uint64_t pp : primeProducts) + if (pp < threshold) + i += 1; + + i = min(i, primes.size() - 1); + maxPrime_ = primes[i]; + primeProduct_ = primeProducts[i]; + + init(); +} + +/// Pre-sieve a small buffer by removing the +/// multiples of primes <= maxPrime. +/// +void PreSieve::init() +{ + size_ = primeProduct_ / 30; + buffer_ = new byte_t[size_]; + deleter_.reset(buffer_); + fill_n(buffer_, size_, 0xff); + + EratSmall eratSmall; + uint64_t stop = primeProduct_ * 2; + eratSmall.init(stop, size_, maxPrime_); + + for (uint64_t prime : primes) + if (prime <= maxPrime_) + eratSmall.addSievingPrime(prime, primeProduct_); + + eratSmall.crossOff(buffer_, size_); +} + +/// Copy pre-sieved buffer to sieve array +void PreSieve::copy(byte_t* sieve, + uint64_t sieveSize, + uint64_t segmentLow) const +{ + // find segmentLow index + uint64_t remainder = segmentLow % primeProduct_; + uint64_t i = remainder / 30; + uint64_t sizeLeft = size_ - i; + + if (sieveSize <= sizeLeft) + copy_n(&buffer_[i], sieveSize, sieve); + else + { + // copy the last remaining bytes of buffer + // to the beginning of the sieve array + copy_n(&buffer_[i], sizeLeft, sieve); + + // restart copying at the beginning of buffer + for (i = sizeLeft; i + size_ < sieveSize; i += size_) + copy_n(buffer_, size_, &sieve[i]); + + copy_n(buffer_, sieveSize - i, &sieve[i]); + } +} + +} // namespace diff -Nru primesieve-6.3+ds/src/PrimeGenerator.cpp primesieve-7.0+ds/src/PrimeGenerator.cpp --- primesieve-6.3+ds/src/PrimeGenerator.cpp 1970-01-01 00:00:00.000000000 +0000 +++ primesieve-7.0+ds/src/PrimeGenerator.cpp 2018-06-08 08:51:41.000000000 +0000 @@ -0,0 +1,222 @@ +/// +/// @file PrimeGenerator.cpp +/// Generates the primes inside [start, stop] and stores them +/// in a vector. After the primes have been stored in the +/// vector primesieve::iterator iterates over the vector and +/// returns the primes. When there are no more primes left in +/// the vector PrimeGenerator generates new primes. +/// +/// Copyright (C) 2018 Kim Walisch, +/// +/// This file is distributed under the BSD License. See the COPYING +/// file in the top level directory. +/// + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +using namespace std; + +namespace primesieve { + +/// First 64 primes +const array PrimeGenerator::smallPrimes = +{ + 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, 229, 233, 239, 241, 251, 257, 263, + 269, 271, 277, 281, 283, 293, 307, 311 +}; + +/// Number of primes <= n +const array PrimeGenerator::primePi = +{ + 0, 0, 1, 2, 2, 3, 3, 4, 4, 4, + 4, 5, 5, 6, 6, 6, 6, 7, 7, 8, + 8, 8, 8, 9, 9, 9, 9, 9, 9, 10, + 10, 11, 11, 11, 11, 11, 11, 12, 12, 12, + 12, 13, 13, 14, 14, 14, 14, 15, 15, 15, + 15, 15, 15, 16, 16, 16, 16, 16, 16, 17, + 17, 18, 18, 18, 18, 18, 18, 19, 19, 19, + 19, 20, 20, 21, 21, 21, 21, 21, 21, 22, + 22, 22, 22, 23, 23, 23, 23, 23, 23, 24, + 24, 24, 24, 24, 24, 24, 24, 25, 25, 25, + 25, 26, 26, 27, 27, 27, 27, 28, 28, 29, + 29, 29, 29, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 31, 31, 31, + 31, 32, 32, 32, 32, 32, 32, 33, 33, 34, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 35, + 35, 36, 36, 36, 36, 36, 36, 37, 37, 37, + 37, 37, 37, 38, 38, 38, 38, 39, 39, 39, + 39, 39, 39, 40, 40, 40, 40, 40, 40, 41, + 41, 42, 42, 42, 42, 42, 42, 42, 42, 42, + 42, 43, 43, 44, 44, 44, 44, 45, 45, 46, + 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, + 46, 47, 47, 47, 47, 47, 47, 47, 47, 47, + 47, 47, 47, 48, 48, 48, 48, 49, 49, 50, + 50, 50, 50, 51, 51, 51, 51, 51, 51, 52, + 52, 53, 53, 53, 53, 53, 53, 53, 53, 53, + 53, 54, 54, 54, 54, 54, 54, 55, 55, 55, + 55, 55, 55, 56, 56, 56, 56, 56, 56, 57, + 57, 58, 58, 58, 58, 58, 58, 59, 59, 59, + 59, 60, 60, 61, 61, 61, 61, 61, 61, 61, + 61, 61, 61, 62, 62, 62, 62, 62, 62, 62, + 62, 62, 62, 62, 62, 62, 62, 63, 63, 63, + 63, 64 +}; + +PrimeGenerator::PrimeGenerator(uint64_t start, uint64_t stop) : + Erat(start, stop), + preSieve_(start, stop) +{ } + +void PrimeGenerator::init() +{ + // sieving is used > max(SmallPrime) + uint64_t sieving = smallPrimes.back() + 1; + uint64_t sieveSize = get_sieve_size(); + start_ = max(start_, sieving); + + Erat::init(start_, stop_, sieveSize, preSieve_); + sievingPrimes_.init(this, preSieve_); + isInit_ = true; +} + +size_t PrimeGenerator::getStartIdx() const +{ + size_t startIdx = 0; + + if (start_ > 1) + startIdx = primePi[start_ - 1]; + + return startIdx; +} + +size_t PrimeGenerator::getStopIdx() const +{ + size_t stopIdx = 0; + + if (stop_ < smallPrimes.back()) + stopIdx = primePi[stop_]; + else + stopIdx = smallPrimes.size(); + + return stopIdx; +} + +void PrimeGenerator::init(vector& primes) +{ + size_t size = primeCountApprox(start_, stop_); + primes.reserve(size); + + if (start_ <= smallPrimes.back()) + { + size_t a = getStartIdx(); + size_t b = getStopIdx(); + + primes.insert(primes.end(), + smallPrimes.begin() + a, + smallPrimes.begin() + b); + } + + init(); +} + +void PrimeGenerator::init(vector& primes, size_t* size) +{ + if (start_ <= smallPrimes.back()) + { + size_t a = getStartIdx(); + size_t b = getStopIdx(); + *size = b - a; + + copy(smallPrimes.begin() + a, + smallPrimes.begin() + b, + primes.begin()); + } + + init(); +} + +bool PrimeGenerator::sieveSegment(vector& primes) +{ + if (!isInit_) + init(primes); + + if (!hasNextSegment()) + return false; + + sieveSegment(); + return true; +} + +bool PrimeGenerator::sieveSegment(vector& primes, size_t* size) +{ + if (!isInit_) + { + init(primes, size); + if (*size > 0) + return false; + } + + if (!hasNextSegment()) + { + *size = 1; + primes[0] = ~0ull; + finished_ = (primes[0] > stop_); + return false; + } + + sieveSegment(); + return true; +} + +void PrimeGenerator::sieveSegment() +{ + uint64_t sqrtHigh = isqrt(segmentHigh_); + + sieveIdx_ = 0; + low_ = segmentLow_; + + if (!prime_) + prime_ = sievingPrimes_.next(); + + while (prime_ <= sqrtHigh) + { + addSievingPrime(prime_); + prime_ = sievingPrimes_.next(); + } + + Erat::sieveSegment(); +} + +void PrimeGenerator::fill(vector& primes) +{ + while (sieveSegment(primes)) + { + for (; sieveIdx_ < sieveSize_; sieveIdx_ += 8) + { + uint64_t bits = littleendian_cast(&sieve_[sieveIdx_]); + + while (bits) + primes.push_back(nextPrime(&bits, low_)); + + low_ += 8 * 30; + } + } +} + +} // namespace diff -Nru primesieve-6.3+ds/src/primesieve/api-c.cpp primesieve-7.0+ds/src/primesieve/api-c.cpp --- primesieve-6.3+ds/src/primesieve/api-c.cpp 2017-11-18 12:38:21.000000000 +0000 +++ primesieve-7.0+ds/src/primesieve/api-c.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,353 +0,0 @@ -/// -/// @file api-c.cpp -/// @brief primesieve C API. -/// Contains the implementations of the functions declared -/// in the primesieve.h header file. -/// -/// Copyright (C) 2017 Kim Walisch, -/// -/// This file is distributed under the BSD License. See the COPYING -/// file in the top level directory. -/// - -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -using namespace primesieve; - -namespace { - -template -void* primes_helper(uint64_t start, uint64_t stop, size_t* size) -{ - try - { - malloc_vector primes; - StorePrimes> sp(primes); - sp.storePrimes(start, stop); - - if (size) - *size = primes.size(); - - primes.disable_free(); - return (void*) primes.data(); - } - catch (std::exception&) - { - errno = EDOM; - if (size) - *size = 0; - } - - return NULL; -} - -template -void* n_primes_helper(uint64_t n, uint64_t start) -{ - try - { - malloc_vector primes; - Store_N_Primes> sp(primes); - sp.storePrimes(n, start); - - primes.disable_free(); - return (void*) primes.data(); - } - catch (std::exception&) - { - errno = EDOM; - } - - return NULL; -} - -} // namespace - -void* primesieve_generate_primes(uint64_t start, uint64_t stop, size_t* size, int type) -{ - switch (type) - { - case SHORT_PRIMES: return primes_helper(start, stop, size); - case USHORT_PRIMES: return primes_helper(start, stop, size); - case INT_PRIMES: return primes_helper(start, stop, size); - case UINT_PRIMES: return primes_helper(start, stop, size); - case LONG_PRIMES: return primes_helper(start, stop, size); - case ULONG_PRIMES: return primes_helper(start, stop, size); - case LONGLONG_PRIMES: return primes_helper(start, stop, size); - case ULONGLONG_PRIMES: return primes_helper(start, stop, size); - case INT16_PRIMES: return primes_helper(start, stop, size); - case UINT16_PRIMES: return primes_helper(start, stop, size); - case INT32_PRIMES: return primes_helper(start, stop, size); - case UINT32_PRIMES: return primes_helper(start, stop, size); - case INT64_PRIMES: return primes_helper(start, stop, size); - case UINT64_PRIMES: return primes_helper(start, stop, size); - } - errno = EDOM; - if (size) - *size = 0; - return NULL; -} - -void* primesieve_generate_n_primes(uint64_t n, uint64_t start, int type) -{ - switch (type) - { - case SHORT_PRIMES: return n_primes_helper(n, start); - case USHORT_PRIMES: return n_primes_helper(n, start); - case INT_PRIMES: return n_primes_helper(n, start); - case UINT_PRIMES: return n_primes_helper(n, start); - case LONG_PRIMES: return n_primes_helper(n, start); - case ULONG_PRIMES: return n_primes_helper(n, start); - case LONGLONG_PRIMES: return n_primes_helper(n, start); - case ULONGLONG_PRIMES: return n_primes_helper(n, start); - case INT16_PRIMES: return n_primes_helper(n, start); - case UINT16_PRIMES: return n_primes_helper(n, start); - case INT32_PRIMES: return n_primes_helper(n, start); - case UINT32_PRIMES: return n_primes_helper(n, start); - case INT64_PRIMES: return n_primes_helper(n, start); - case UINT64_PRIMES: return n_primes_helper(n, start); - } - errno = EDOM; - return NULL; -} - -void primesieve_free(void* primes) -{ - free(primes); -} - -uint64_t primesieve_nth_prime(int64_t n, uint64_t start) -{ - try - { - ParallelPrimeSieve pps; - pps.setSieveSize(get_sieve_size()); - pps.setNumThreads(get_num_threads()); - return pps.nthPrime(n, start); - } - catch (std::exception&) - { - errno = EDOM; - } - return PRIMESIEVE_ERROR; -} - -uint64_t primesieve_count_primes(uint64_t start, uint64_t stop) -{ - try - { - ParallelPrimeSieve pps; - pps.setSieveSize(get_sieve_size()); - pps.setNumThreads(get_num_threads()); - return pps.countPrimes(start, stop); - } - catch (std::exception&) - { - errno = EDOM; - } - return PRIMESIEVE_ERROR; -} - -uint64_t primesieve_count_twins(uint64_t start, uint64_t stop) -{ - try - { - ParallelPrimeSieve pps; - pps.setSieveSize(get_sieve_size()); - pps.setNumThreads(get_num_threads()); - return pps.countTwins(start, stop); - } - catch (std::exception&) - { - errno = EDOM; - } - return PRIMESIEVE_ERROR; -} - -uint64_t primesieve_count_triplets(uint64_t start, uint64_t stop) -{ - try - { - ParallelPrimeSieve pps; - pps.setSieveSize(get_sieve_size()); - pps.setNumThreads(get_num_threads()); - return pps.countTriplets(start, stop); - } - catch (std::exception&) - { - errno = EDOM; - } - return PRIMESIEVE_ERROR; -} - -uint64_t primesieve_count_quadruplets(uint64_t start, uint64_t stop) -{ - try - { - ParallelPrimeSieve pps; - pps.setSieveSize(get_sieve_size()); - pps.setNumThreads(get_num_threads()); - return pps.countQuadruplets(start, stop); - } - catch (std::exception&) - { - errno = EDOM; - } - return PRIMESIEVE_ERROR; -} - -uint64_t primesieve_count_quintuplets(uint64_t start, uint64_t stop) -{ - try - { - ParallelPrimeSieve pps; - pps.setSieveSize(get_sieve_size()); - pps.setNumThreads(get_num_threads()); - return pps.countQuintuplets(start, stop); - } - catch (std::exception&) - { - errno = EDOM; - } - return PRIMESIEVE_ERROR; -} - -uint64_t primesieve_count_sextuplets(uint64_t start, uint64_t stop) -{ - try - { - ParallelPrimeSieve pps; - pps.setSieveSize(get_sieve_size()); - pps.setNumThreads(get_num_threads()); - return pps.countSextuplets(start, stop); - } - catch (std::exception&) - { - errno = EDOM; - } - return PRIMESIEVE_ERROR; -} - -void primesieve_print_primes(uint64_t start, uint64_t stop) -{ - try - { - PrimeSieve ps; - ps.setSieveSize(get_sieve_size()); - ps.printPrimes(start, stop); - } - catch (std::exception&) - { - errno = EDOM; - } -} - -void primesieve_print_twins(uint64_t start, uint64_t stop) -{ - try - { - PrimeSieve ps; - ps.setSieveSize(get_sieve_size()); - ps.printTwins(start, stop); - } - catch (std::exception&) - { - errno = EDOM; - } -} - -void primesieve_print_triplets(uint64_t start, uint64_t stop) -{ - try - { - PrimeSieve ps; - ps.setSieveSize(get_sieve_size()); - ps.printTriplets(start, stop); - } - catch (std::exception&) - { - errno = EDOM; - } -} - -void primesieve_print_quadruplets(uint64_t start, uint64_t stop) -{ - try - { - PrimeSieve ps; - ps.setSieveSize(get_sieve_size()); - ps.printQuadruplets(start, stop); - } - catch (std::exception&) - { - errno = EDOM; - } -} - -void primesieve_print_quintuplets(uint64_t start, uint64_t stop) -{ - try - { - PrimeSieve ps; - ps.setSieveSize(get_sieve_size()); - ps.printQuintuplets(start, stop); - } - catch (std::exception&) - { - errno = EDOM; - } -} - -void primesieve_print_sextuplets(uint64_t start, uint64_t stop) -{ - try - { - PrimeSieve ps; - ps.setSieveSize(get_sieve_size()); - ps.printSextuplets(start, stop); - } - catch (std::exception&) - { - errno = EDOM; - } -} - -int primesieve_get_sieve_size() -{ - return get_sieve_size(); -} - -int primesieve_get_num_threads() -{ - return get_num_threads(); -} - -void primesieve_set_sieve_size(int sieve_size) -{ - set_sieve_size(sieve_size); -} - -void primesieve_set_num_threads(int num_threads) -{ - set_num_threads(num_threads); -} - -uint64_t primesieve_get_max_stop() -{ - return get_max_stop(); -} - -const char* primesieve_version() -{ - return PRIMESIEVE_VERSION; -} diff -Nru primesieve-6.3+ds/src/primesieve/api.cpp primesieve-7.0+ds/src/primesieve/api.cpp --- primesieve-6.3+ds/src/primesieve/api.cpp 2017-11-18 12:38:21.000000000 +0000 +++ primesieve-7.0+ds/src/primesieve/api.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,199 +0,0 @@ -/// -/// @file api.cpp -/// @brief primesieve C++ API. -/// Contains the implementations of the functions declared -/// in the primesieve.hpp header file. -/// -/// Copyright (C) 2017 Kim Walisch, -/// -/// This file is distributed under the BSD License. See the COPYING -/// file in the top level directory. -/// - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -namespace { - -int sieve_size = 0; - -int num_threads = 0; - -} - -namespace primesieve { - -uint64_t nth_prime(int64_t n, uint64_t start) -{ - ParallelPrimeSieve pps; - pps.setSieveSize(get_sieve_size()); - pps.setNumThreads(get_num_threads()); - return pps.nthPrime(n, start); -} - -uint64_t count_primes(uint64_t start, uint64_t stop) -{ - ParallelPrimeSieve pps; - pps.setSieveSize(get_sieve_size()); - pps.setNumThreads(get_num_threads()); - return pps.countPrimes(start, stop); -} - -uint64_t count_twins(uint64_t start, uint64_t stop) -{ - ParallelPrimeSieve pps; - pps.setSieveSize(get_sieve_size()); - pps.setNumThreads(get_num_threads()); - return pps.countTwins(start, stop); -} - -uint64_t count_triplets(uint64_t start, uint64_t stop) -{ - ParallelPrimeSieve pps; - pps.setSieveSize(get_sieve_size()); - pps.setNumThreads(get_num_threads()); - return pps.countTriplets(start, stop); -} - -uint64_t count_quadruplets(uint64_t start, uint64_t stop) -{ - ParallelPrimeSieve pps; - pps.setSieveSize(get_sieve_size()); - pps.setNumThreads(get_num_threads()); - return pps.countQuadruplets(start, stop); -} - -uint64_t count_quintuplets(uint64_t start, uint64_t stop) -{ - ParallelPrimeSieve pps; - pps.setSieveSize(get_sieve_size()); - pps.setNumThreads(get_num_threads()); - return pps.countQuintuplets(start, stop); -} - -uint64_t count_sextuplets(uint64_t start, uint64_t stop) -{ - ParallelPrimeSieve pps; - pps.setSieveSize(get_sieve_size()); - pps.setNumThreads(get_num_threads()); - return pps.countSextuplets(start, stop); -} - -void print_primes(uint64_t start, uint64_t stop) -{ - PrimeSieve ps; - ps.setSieveSize(get_sieve_size()); - ps.printPrimes(start, stop); -} - -void print_twins(uint64_t start, uint64_t stop) -{ - PrimeSieve ps; - ps.setSieveSize(get_sieve_size()); - ps.printTwins(start, stop); -} - -void print_triplets(uint64_t start, uint64_t stop) -{ - PrimeSieve ps; - ps.setSieveSize(get_sieve_size()); - ps.printTriplets(start, stop); -} - -void print_quadruplets(uint64_t start, uint64_t stop) -{ - PrimeSieve ps; - ps.setSieveSize(get_sieve_size()); - ps.printQuadruplets(start, stop); -} - -void print_quintuplets(uint64_t start, uint64_t stop) -{ - PrimeSieve ps; - ps.setSieveSize(get_sieve_size()); - ps.printQuintuplets(start, stop); -} - -void print_sextuplets(uint64_t start, uint64_t stop) -{ - PrimeSieve ps; - ps.setSieveSize(get_sieve_size()); - ps.printSextuplets(start, stop); -} - -int get_num_threads() -{ - if (num_threads) - return num_threads; - else - return ParallelPrimeSieve::getMaxThreads(); -} - -void set_num_threads(int threads) -{ - num_threads = inBetween(1, threads, ParallelPrimeSieve::getMaxThreads()); -} - -uint64_t get_max_stop() -{ - return std::numeric_limits::max(); -} - -std::string primesieve_version() -{ - return PRIMESIEVE_VERSION; -} - -void set_sieve_size(int kilobytes) -{ - sieve_size = inBetween(8, kilobytes, 4096); - sieve_size = floorPow2(sieve_size); -} - -int get_sieve_size() -{ - // user specified sieve size - if (sieve_size) - return sieve_size; - - size_t l1CacheSize = cpuInfo.l1CacheSize(); - size_t l2CacheSize = cpuInfo.l2CacheSize(); - - // convert to kilobytes - l1CacheSize /= 1024; - l2CacheSize /= 1024; - - // check if each CPU core has a private L2 cache - if (cpuInfo.hasL2Cache() && - cpuInfo.privateL2Cache() && - l2CacheSize > l1CacheSize) - { - l2CacheSize = inBetween(32, l2CacheSize, 4096); - l2CacheSize = floorPow2(l2CacheSize); - return (int) l2CacheSize; - } - else - { - if (!cpuInfo.hasL1Cache()) - l1CacheSize = 32; - - // if the CPU does not have an L2 cache or if the - // cache is shared between all CPU cores we - // set the sieve size to the CPU's L1 cache size - - l1CacheSize = inBetween(8, l1CacheSize, 4096); - l1CacheSize = floorPow2(l1CacheSize); - return (int) l1CacheSize; - } -} - -} // namespace diff -Nru primesieve-6.3+ds/src/primesieve/CpuInfo.cpp primesieve-7.0+ds/src/primesieve/CpuInfo.cpp --- primesieve-6.3+ds/src/primesieve/CpuInfo.cpp 2017-11-18 12:38:21.000000000 +0000 +++ primesieve-7.0+ds/src/primesieve/CpuInfo.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,344 +0,0 @@ -/// -/// @file CpuInfo.cpp -/// @brief Get the CPUs' cache sizes in bytes -/// -/// Copyright (C) 2017 Kim Walisch, -/// -/// This file is distributed under the BSD License. See the COPYING -/// file in the top level directory. -/// - -#include - -#include -#include -#include - -#if defined(__APPLE__) - #if !defined(__has_include) - #define APPLE_SYSCTL - #elif __has_include() && \ - __has_include() - #define APPLE_SYSCTL - #endif -#endif - -#if defined(_WIN32) - -#include -#include - -#elif defined(APPLE_SYSCTL) - -#include -#include -#include - -#else // all other OSes - -#include -#include - -using namespace std; - -namespace { - -string getString(const string& filename) -{ - ifstream file(filename); - string str; - - if (file) - { - // https://stackoverflow.com/a/3177560/363778 - stringstream trimmer; - trimmer << file.rdbuf(); - trimmer >> str; - } - - return str; -} - -size_t getValue(const string& filename) -{ - size_t val = 0; - string str = getString(filename); - - if (!str.empty()) - { - val = stol(str); - - // Last character may be: - // 'K' = kilobytes - // 'M' = megabytes - // 'G' = gigabytes - if (str.back() == 'K') - val *= 1024; - if (str.back() == 'M') - val *= 1024 * 1024; - if (str.back() == 'G') - val *= 1024 * 1024 * 1024; - } - - return val; -} - -} // namespace - -#endif - -using namespace std; - -namespace primesieve { - -CpuInfo::CpuInfo() - : l1CacheSize_(0), - l2CacheSize_(0), - privateL2Cache_(false) -{ - try - { - initCache(); - } - catch (exception& e) - { - error_ = e.what(); - } -} - -size_t CpuInfo::l1CacheSize() const -{ - return l1CacheSize_; -} - -size_t CpuInfo::l2CacheSize() const -{ - return l2CacheSize_; -} - -bool CpuInfo::privateL2Cache() const -{ - return privateL2Cache_; -} - -string CpuInfo::getError() const -{ - return error_; -} - -bool CpuInfo::hasL1Cache() const -{ - return l1CacheSize_ >= (1 << 12) && - l1CacheSize_ <= (1ull << 40); -} - -bool CpuInfo::hasL2Cache() const -{ - return l2CacheSize_ >= (1 << 12) && - l2CacheSize_ <= (1ull << 40); -} - -#if defined(APPLE_SYSCTL) - -void CpuInfo::initCache() -{ - size_t l1Length = sizeof(l1CacheSize_); - size_t l2Length = sizeof(l2CacheSize_); - - sysctlbyname("hw.l1dcachesize", &l1CacheSize_, &l1Length, NULL, 0); - sysctlbyname("hw.l2cachesize" , &l2CacheSize_, &l2Length, NULL, 0); - - size_t size = 0; - - if (!sysctlbyname("hw.cacheconfig", NULL, &size, NULL, 0)) - { - size_t n = size / sizeof(size); - vector cacheconfig(n); - - if (cacheconfig.size() > 2) - { - // https://developer.apple.com/library/content/releasenotes/Performance/RN-AffinityAPI/index.html - sysctlbyname("hw.cacheconfig" , &cacheconfig[0], &size, NULL, 0); - size_t l2Sharing = cacheconfig[2]; - - if (l2Sharing <= 1) - privateL2Cache_ = true; - else - { - size_t logicalcpu = 1; - size = sizeof(size); - sysctlbyname("hw.logicalcpu", &logicalcpu, &size, NULL, 0); - logicalcpu = max(1, logicalcpu); - - size_t physicalcpu = 1; - size = sizeof(size); - sysctlbyname("hw.physicalcpu", &physicalcpu, &size, NULL, 0); - physicalcpu = max(1, physicalcpu); - - if (l2Sharing <= logicalcpu / physicalcpu) - privateL2Cache_ = true; - } - } - } -} - -#elif defined(_WIN32) - -void CpuInfo::initCache() -{ - typedef BOOL (WINAPI *LPFN_GLPI)(PSYSTEM_LOGICAL_PROCESSOR_INFORMATION, PDWORD); - - LPFN_GLPI glpi = (LPFN_GLPI) GetProcAddress(GetModuleHandle(TEXT("kernel32")), "GetLogicalProcessorInformation"); - - if (!glpi) - return; - - DWORD bytes = 0; - glpi(0, &bytes); - - if (!bytes) - return; - - size_t threadsPerCore = 0; - size_t size = bytes / sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION); - vector info(size); - - if (!glpi(&info[0], &bytes)) - return; - - for (size_t i = 0; i < size; i++) - { - if (info[i].Relationship == RelationProcessorCore) - { - auto mask = info[i].ProcessorMask; - - // ProcessorMask contains one bit set for - // each logical CPU core related to the - // current physical CPU core - for (threadsPerCore = 0; mask > 0; threadsPerCore++) - mask &= mask - 1; - } - - if (info[i].Relationship == RelationCache && - (info[i].Cache.Type == CacheData || - info[i].Cache.Type == CacheUnified)) - { - if (info[i].Cache.Level == 1) - l1CacheSize_ = info[i].Cache.Size; - if (info[i].Cache.Level == 2) - l2CacheSize_ = info[i].Cache.Size; - - // if the CPU has an L3 cache we assume - // the L2 cache is private - if (info[i].Cache.Level == 3 && - info[i].Cache.Size > 0) - privateL2Cache_ = true; - } - } - -// Windows 7 (2009) or later -#if _WIN32_WINNT >= 0x0601 - - typedef BOOL (WINAPI *LPFN_GLPIEX)(LOGICAL_PROCESSOR_RELATIONSHIP, PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX, PDWORD); - - LPFN_GLPIEX glpiex = (LPFN_GLPIEX) GetProcAddress( - GetModuleHandle(TEXT("kernel32")), "GetLogicalProcessorInformationEx"); - - if (!glpiex) - return; - - bytes = 0; - glpiex(RelationAll, 0, &bytes); - - if (!bytes) - return; - - vector buffer(bytes); - SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX* cpu; - - if (!glpiex(RelationAll, (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX*) &buffer[0], &bytes)) - return; - - for (size_t i = 0; i < bytes; i += cpu->Size) - { - cpu = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX*) &buffer[i]; - - // check L2 cache - if (cpu->Relationship == RelationCache && - cpu->Cache.GroupMask.Group == 0 && - cpu->Cache.Level == 2 && - (cpu->Cache.Type == CacheData || - cpu->Cache.Type == CacheUnified)) - { - // @warning: GetLogicalProcessorInformationEx() reports - // incorrect data when Windows is run inside a virtual - // machine. Specifically the GROUP_AFFINITY.Mask will - // only have 1 or 2 bits set for each CPU cache (L1, L2 and - // L3) even if more logical CPU cores share the cache - auto mask = cpu->Cache.GroupMask.Mask; - size_t l2Sharing = 0; - - // Cache.GroupMask.Mask contains one bit set for - // each logical CPU core sharing the cache - for (; mask > 0; l2Sharing++) - mask &= mask - 1; - - // the L2 cache is private if it is tied to a physical CPU core - privateL2Cache_ = (l2Sharing <= threadsPerCore); - - break; - } - } - -#endif -} - -#else - -/// This works on Linux and Android. We also use this -/// for all unknown OSes, it might work. -/// -void CpuInfo::initCache() -{ - for (int i = 0; i <= 3; i++) - { - string filename = "/sys/devices/system/cpu/cpu0/cache/index" + to_string(i); - string threadSiblingsList = "/sys/devices/system/cpu/cpu0/topology/thread_siblings_list"; - - string cacheLevel = filename + "/level"; - string cacheSize = filename + "/size"; - string sharedCpuList = filename + "/shared_cpu_list"; - string cacheType = filename + "/type"; - - size_t level = getValue(cacheLevel); - string type = getString(cacheType); - - if (level == 1 && - (type == "Data" || - type == "Unified")) - { - l1CacheSize_ = getValue(cacheSize); - } - - if (level == 2 && - (type == "Data" || - type == "Unified")) - { - l2CacheSize_ = getValue(cacheSize); - sharedCpuList = getString(sharedCpuList); - threadSiblingsList = getString(threadSiblingsList); - - // https://lwn.net/Articles/254445/ - if (!sharedCpuList.empty() && - sharedCpuList == threadSiblingsList) - privateL2Cache_ = true; - } - } -} - -#endif - -/// Singleton -const CpuInfo cpuInfo; - -} // namespace diff -Nru primesieve-6.3+ds/src/primesieve/EratBig.cpp primesieve-7.0+ds/src/primesieve/EratBig.cpp --- primesieve-6.3+ds/src/primesieve/EratBig.cpp 2017-11-18 12:38:21.000000000 +0000 +++ primesieve-7.0+ds/src/primesieve/EratBig.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,180 +0,0 @@ -/// -/// @file EratBig.cpp -/// @brief Segmented sieve of Eratosthenes optimized for big sieving -/// primes. This is an optimized implementation of Tomas -/// Oliveira e Silva's cache-friendly bucket sieve algorithm: -/// http://www.ieeta.pt/~tos/software/prime_sieve.html -/// -/// Copyright (C) 2017 Kim Walisch, -/// -/// This file is distributed under the BSD License. See the COPYING -/// file in the top level directory. -/// - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -using namespace std; - -namespace primesieve { - -/// @stop: Upper bound for sieving -/// @sieveSize: Sieve size in bytes -/// @maxPrime: Sieving primes <= maxPrime -/// -EratBig::EratBig(uint64_t stop, uint64_t sieveSize, uint64_t maxPrime) : - Wheel210_t(stop, sieveSize), - maxPrime_(maxPrime), - log2SieveSize_(ilog2(sieveSize)), - moduloSieveSize_(sieveSize - 1), - stock_(nullptr) -{ - // '>> log2SieveSize' requires power of 2 sieveSize - if (!isPow2(sieveSize)) - throw primesieve_error("EratBig: sieveSize must be a power of 2"); - init(sieveSize); -} - -void EratBig::init(uint64_t sieveSize) -{ - uint64_t maxSievingPrime = maxPrime_ / NUMBERS_PER_BYTE; - uint64_t maxNextMultiple = maxSievingPrime * getMaxFactor() + getMaxFactor(); - uint64_t maxMultipleIndex = sieveSize - 1 + maxNextMultiple; - uint64_t maxSegmentCount = maxMultipleIndex >> log2SieveSize_; - uint64_t size = maxSegmentCount + 1; - - // EratBig uses up to 1.6 gigabytes of memory - memory_.reserve(((1u << 30) * 2) / config::BYTES_PER_ALLOC); - - lists_.resize(size, nullptr); - for (uint64_t i = 0; i < size; i++) - pushBucket(i); -} - -/// Add a new sieving prime to EratBig -void EratBig::storeSievingPrime(uint64_t prime, uint64_t multipleIndex, uint64_t wheelIndex) -{ - assert(prime <= maxPrime_); - uint64_t sievingPrime = prime / NUMBERS_PER_BYTE; - uint64_t segment = multipleIndex >> log2SieveSize_; - multipleIndex &= moduloSieveSize_; - - if (!lists_[segment]->store(sievingPrime, multipleIndex, wheelIndex)) - pushBucket(segment); -} - -/// Add an empty bucket to the front of lists_[segment] -void EratBig::pushBucket(uint64_t segment) -{ - // allocate new buckets - if (!stock_) - { - int N = config::BYTES_PER_ALLOC / sizeof(Bucket); - memory_.emplace_back(unique_ptr(new Bucket[N])); - Bucket* bucket = memory_.back().get(); - - for (int i = 0; i < N - 1; i++) - bucket[i].setNext(&bucket[i + 1]); - bucket[N-1].setNext(nullptr); - stock_ = bucket; - } - Bucket* emptyBucket = stock_; - stock_ = stock_->next(); - moveBucket(*emptyBucket, lists_[segment]); -} - -void EratBig::moveBucket(Bucket& src, Bucket*& dest) -{ - src.setNext(dest); - dest = &src; -} - -/// Cross-off the multiples of big sieving -/// primes from the sieve array -/// -void EratBig::crossOff(byte_t* sieve) -{ - while (lists_[0]->hasNext() || !lists_[0]->empty()) - { - Bucket* bucket = lists_[0]; - lists_[0] = nullptr; - pushBucket(0); - do { - crossOff(sieve, bucket->begin(), bucket->end()); - Bucket* processed = bucket; - bucket = bucket->next(); - processed->reset(); - moveBucket(*processed, stock_); - } while (bucket); - } - - rotate(lists_.begin(), lists_.begin() + 1, lists_.end()); -} - -/// Segmented sieve of Eratosthenes with wheel factorization -/// optimized for big sieving primes that have very few -/// multiples per segment. Cross-off the next multiple of -/// each sieving prime in the current bucket -/// -void EratBig::crossOff(byte_t* sieve, SievingPrime* primes, SievingPrime* end) -{ - Bucket** lists = &lists_[0]; - uint64_t moduloSieveSize = moduloSieveSize_; - uint64_t log2SieveSize = log2SieveSize_; - - // 2 sieving primes are processed per loop iteration - // to increase instruction level parallelism - for (; primes + 2 <= end; primes += 2) - { - uint64_t multipleIndex0 = primes[0].getMultipleIndex(); - uint64_t wheelIndex0 = primes[0].getWheelIndex(); - uint64_t sievingPrime0 = primes[0].getSievingPrime(); - uint64_t multipleIndex1 = primes[1].getMultipleIndex(); - uint64_t wheelIndex1 = primes[1].getWheelIndex(); - uint64_t sievingPrime1 = primes[1].getSievingPrime(); - - // cross-off the current multiple (unset bit) - // and calculate the next multiple - unsetBit(sieve, sievingPrime0, &multipleIndex0, &wheelIndex0); - unsetBit(sieve, sievingPrime1, &multipleIndex1, &wheelIndex1); - - uint64_t segment0 = multipleIndex0 >> log2SieveSize; - uint64_t segment1 = multipleIndex1 >> log2SieveSize; - - multipleIndex0 &= moduloSieveSize; - multipleIndex1 &= moduloSieveSize; - - // move the 2 sieving primes to the list related - // to their next multiple - if (!lists[segment0]->store(sievingPrime0, multipleIndex0, wheelIndex0)) - pushBucket(segment0); - if (!lists[segment1]->store(sievingPrime1, multipleIndex1, wheelIndex1)) - pushBucket(segment1); - } - - if (primes != end) - { - uint64_t multipleIndex = primes->getMultipleIndex(); - uint64_t wheelIndex = primes->getWheelIndex(); - uint64_t sievingPrime = primes->getSievingPrime(); - - unsetBit(sieve, sievingPrime, &multipleIndex, &wheelIndex); - uint64_t segment = multipleIndex >> log2SieveSize; - multipleIndex &= moduloSieveSize; - - if (!lists[segment]->store(sievingPrime, multipleIndex, wheelIndex)) - pushBucket(segment); - } -} - -} // namespace diff -Nru primesieve-6.3+ds/src/primesieve/EratMedium.cpp primesieve-7.0+ds/src/primesieve/EratMedium.cpp --- primesieve-6.3+ds/src/primesieve/EratMedium.cpp 2017-11-18 12:38:21.000000000 +0000 +++ primesieve-7.0+ds/src/primesieve/EratMedium.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,112 +0,0 @@ -/// -/// @file EratMedium.cpp -/// @brief Segmented sieve of Eratosthenes optimized for -/// medium sieving primes. -/// -/// Copyright (C) 2017 Kim Walisch, -/// -/// This file is distributed under the BSD License. See the COPYING -/// file in the top level directory. -/// - -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -namespace primesieve { - -/// @stop: Upper bound for sieving -/// @sieveSize: Sieve size in bytes -/// @maxPrime: Sieving primes <= maxPrime -/// -EratMedium::EratMedium(uint64_t stop, uint64_t sieveSize, uint64_t maxPrime) : - Wheel210_t(stop, sieveSize), - maxPrime_(maxPrime) -{ - // ensure multipleIndex < 2^23 in crossOff() - if (sieveSize > (4096u << 10)) - throw primesieve_error("EratMedium: sieveSize must be <= 4096 kilobytes"); - if (maxPrime_ > sieveSize * 5) - throw primesieve_error("EratMedium: maxPrime must be <= sieveSize * 5"); - - size_t size = prime_count_approx(maxPrime); - primes_.reserve(size); -} - -/// Add a new sieving prime to EratMedium -void EratMedium::storeSievingPrime(uint64_t prime, uint64_t multipleIndex, uint64_t wheelIndex) -{ - assert(prime <= maxPrime_); - uint64_t sievingPrime = prime / NUMBERS_PER_BYTE; - primes_.emplace_back(sievingPrime, multipleIndex, wheelIndex); -} - -/// Segmented sieve of Eratosthenes with wheel factorization -/// optimized for medium sieving primes that have a -/// few multiples per segment -/// -void EratMedium::crossOff(byte_t* sieve, uint64_t sieveSize) -{ - size_t i = 0; - size_t size = primes_.size(); - auto primes = primes_.data(); - - // process 3 sieving primes per loop iteration to - // increase instruction level parallelism - for (; i < size - size % 3; i += 3) - { - uint64_t multipleIndex0 = primes[i + 0].getMultipleIndex(); - uint64_t wheelIndex0 = primes[i + 0].getWheelIndex(); - uint64_t sievingPrime0 = primes[i + 0].getSievingPrime(); - uint64_t multipleIndex1 = primes[i + 1].getMultipleIndex(); - uint64_t wheelIndex1 = primes[i + 1].getWheelIndex(); - uint64_t sievingPrime1 = primes[i + 1].getSievingPrime(); - uint64_t multipleIndex2 = primes[i + 2].getMultipleIndex(); - uint64_t wheelIndex2 = primes[i + 2].getWheelIndex(); - uint64_t sievingPrime2 = primes[i + 2].getSievingPrime(); - - while (multipleIndex0 < sieveSize) - { - unsetBit(sieve, sievingPrime0, &multipleIndex0, &wheelIndex0); - if (multipleIndex1 >= sieveSize) break; - unsetBit(sieve, sievingPrime1, &multipleIndex1, &wheelIndex1); - if (multipleIndex2 >= sieveSize) break; - unsetBit(sieve, sievingPrime2, &multipleIndex2, &wheelIndex2); - } - - while (multipleIndex0 < sieveSize) unsetBit(sieve, sievingPrime0, &multipleIndex0, &wheelIndex0); - while (multipleIndex1 < sieveSize) unsetBit(sieve, sievingPrime1, &multipleIndex1, &wheelIndex1); - while (multipleIndex2 < sieveSize) unsetBit(sieve, sievingPrime2, &multipleIndex2, &wheelIndex2); - - multipleIndex0 -= sieveSize; - multipleIndex1 -= sieveSize; - multipleIndex2 -= sieveSize; - - primes[i + 0].set(multipleIndex0, wheelIndex0); - primes[i + 1].set(multipleIndex1, wheelIndex1); - primes[i + 2].set(multipleIndex2, wheelIndex2); - } - - // process remaining sieving primes - for (; i < size; i++) - { - uint64_t multipleIndex = primes[i].getMultipleIndex(); - uint64_t wheelIndex = primes[i].getWheelIndex(); - uint64_t sievingPrime = primes[i].getSievingPrime(); - - while (multipleIndex < sieveSize) - unsetBit(sieve, sievingPrime, &multipleIndex, &wheelIndex); - - multipleIndex -= sieveSize; - primes[i].set(multipleIndex, wheelIndex); - } -} - -} // namespace diff -Nru primesieve-6.3+ds/src/primesieve/EratSmall.cpp primesieve-7.0+ds/src/primesieve/EratSmall.cpp --- primesieve-6.3+ds/src/primesieve/EratSmall.cpp 2017-11-18 12:38:21.000000000 +0000 +++ primesieve-7.0+ds/src/primesieve/EratSmall.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,365 +0,0 @@ -/// -/// @file EratSmall.cpp -/// @brief Segmented sieve of Eratosthenes optimized for -/// small sieving primes. -/// -/// Copyright (C) 2017 Kim Walisch, -/// -/// This file is distributed under the BSD License. See the COPYING -/// file in the top level directory. -/// - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -using namespace std; - -namespace primesieve { - -/// @stop: Upper bound for sieving -/// @l1Size: Sieve size in bytes -/// @maxPrime: Sieving primes <= maxPrime -/// -EratSmall::EratSmall(uint64_t stop, uint64_t l1Size, uint64_t maxPrime) : - Wheel30_t(stop, l1Size), - maxPrime_(maxPrime), - l1Size_(l1Size) -{ - if (maxPrime_ > l1Size * 3) - throw primesieve_error("EratSmall: maxPrime must be <= l1Size * 3"); - - size_t count = prime_count_approx(maxPrime); - primes_.reserve(count); -} - -/// Usually sieve size = L2 cache size, -/// but EratSmall runs faster using -/// sieve size = L1 cache size -/// -uint64_t EratSmall::getL1Size(uint64_t sieveSize) -{ - if (!cpuInfo.hasL1Cache()) - return sieveSize; - - uint64_t size = cpuInfo.l1CacheSize(); - uint64_t minSize = 8 << 10; - uint64_t maxSize = 4096 << 10; - - size = inBetween(minSize, size, maxSize); - - return size; -} - -/// Add a new sieving prime to EratSmall -void EratSmall::storeSievingPrime(uint64_t prime, uint64_t multipleIndex, uint64_t wheelIndex) -{ - assert(prime <= maxPrime_); - uint64_t sievingPrime = prime / NUMBERS_PER_BYTE; - primes_.emplace_back(sievingPrime, multipleIndex, wheelIndex); -} - -/// Cross-off the multiples of small sieving -/// primes from the sieve array -/// -void EratSmall::crossOff(byte_t* sieve, uint64_t sieveSize) -{ - byte_t* sieveEnd = &sieve[sieveSize]; - - for (; sieve < sieveEnd; sieve += l1Size_) - { - byte_t* end = &sieve[l1Size_]; - end = min(end, sieveEnd); - crossOff(sieve, end); - } -} - -/// Segmented sieve of Eratosthenes with wheel factorization -/// optimized for small sieving primes that have many multiples -/// per segment. This algorithm uses a hardcoded modulo 30 -/// wheel that skips multiples of 2, 3 and 5 -/// -void EratSmall::crossOff(byte_t* sieve, byte_t* sieveEnd) -{ - for (auto& prime : primes_) - { - uint64_t sievingPrime = prime.getSievingPrime(); - uint64_t multipleIndex = prime.getMultipleIndex(); - uint64_t wheelIndex = prime.getWheelIndex(); - - // pointer to the byte containing the first multiple - // of sievingPrime within the current segment - byte_t* p = &sieve[multipleIndex]; - byte_t* loopLimit = sieveEnd - (sievingPrime * 28 + 27); - if (loopLimit > sieveEnd) - loopLimit = p; - - switch (wheelIndex) - { - for (;;) // i*30 + 7 - { - case 0: // each iteration removes the next 8 multiples - // of the current sievingPrime - for (; p < loopLimit; p += sievingPrime * 30 + 7) - { - p[sievingPrime * 0 + 0] &= BIT0; - p[sievingPrime * 6 + 1] &= BIT4; - p[sievingPrime * 10 + 2] &= BIT3; - p[sievingPrime * 12 + 2] &= BIT7; - p[sievingPrime * 16 + 3] &= BIT6; - p[sievingPrime * 18 + 4] &= BIT2; - p[sievingPrime * 22 + 5] &= BIT1; - p[sievingPrime * 28 + 6] &= BIT5; - } - if (p >= sieveEnd) { prime.setWheelIndex(0); break; } - *p &= BIT0; p += sievingPrime * 6 + 1; - case 1: if (p >= sieveEnd) { prime.setWheelIndex(1); break; } - *p &= BIT4; p += sievingPrime * 4 + 1; - case 2: if (p >= sieveEnd) { prime.setWheelIndex(2); break; } - *p &= BIT3; p += sievingPrime * 2 + 0; - case 3: if (p >= sieveEnd) { prime.setWheelIndex(3); break; } - *p &= BIT7; p += sievingPrime * 4 + 1; - case 4: if (p >= sieveEnd) { prime.setWheelIndex(4); break; } - *p &= BIT6; p += sievingPrime * 2 + 1; - case 5: if (p >= sieveEnd) { prime.setWheelIndex(5); break; } - *p &= BIT2; p += sievingPrime * 4 + 1; - case 6: if (p >= sieveEnd) { prime.setWheelIndex(6); break; } - *p &= BIT1; p += sievingPrime * 6 + 1; - case 7: if (p >= sieveEnd) { prime.setWheelIndex(7); break; } - *p &= BIT5; p += sievingPrime * 2 + 1; - } - break; - for (;;) // i*30 + 11 - { - case 8: for (; p < loopLimit; p += sievingPrime * 30 + 11) - { - p[sievingPrime * 0 + 0] &= BIT1; - p[sievingPrime * 6 + 2] &= BIT3; - p[sievingPrime * 10 + 3] &= BIT7; - p[sievingPrime * 12 + 4] &= BIT5; - p[sievingPrime * 16 + 6] &= BIT0; - p[sievingPrime * 18 + 6] &= BIT6; - p[sievingPrime * 22 + 8] &= BIT2; - p[sievingPrime * 28 + 10] &= BIT4; - } - if (p >= sieveEnd) { prime.setWheelIndex(8); break; } - *p &= BIT1; p += sievingPrime * 6 + 2; - case 9: if (p >= sieveEnd) { prime.setWheelIndex(9); break; } - *p &= BIT3; p += sievingPrime * 4 + 1; - case 10: if (p >= sieveEnd) { prime.setWheelIndex(10); break; } - *p &= BIT7; p += sievingPrime * 2 + 1; - case 11: if (p >= sieveEnd) { prime.setWheelIndex(11); break; } - *p &= BIT5; p += sievingPrime * 4 + 2; - case 12: if (p >= sieveEnd) { prime.setWheelIndex(12); break; } - *p &= BIT0; p += sievingPrime * 2 + 0; - case 13: if (p >= sieveEnd) { prime.setWheelIndex(13); break; } - *p &= BIT6; p += sievingPrime * 4 + 2; - case 14: if (p >= sieveEnd) { prime.setWheelIndex(14); break; } - *p &= BIT2; p += sievingPrime * 6 + 2; - case 15: if (p >= sieveEnd) { prime.setWheelIndex(15); break; } - *p &= BIT4; p += sievingPrime * 2 + 1; - } - break; - for (;;) // i*30 + 13 - { - case 16: for (; p < loopLimit; p += sievingPrime * 30 + 13) - { - p[sievingPrime * 0 + 0] &= BIT2; - p[sievingPrime * 6 + 2] &= BIT7; - p[sievingPrime * 10 + 4] &= BIT5; - p[sievingPrime * 12 + 5] &= BIT4; - p[sievingPrime * 16 + 7] &= BIT1; - p[sievingPrime * 18 + 8] &= BIT0; - p[sievingPrime * 22 + 9] &= BIT6; - p[sievingPrime * 28 + 12] &= BIT3; - } - if (p >= sieveEnd) { prime.setWheelIndex(16); break; } - *p &= BIT2; p += sievingPrime * 6 + 2; - case 17: if (p >= sieveEnd) { prime.setWheelIndex(17); break; } - *p &= BIT7; p += sievingPrime * 4 + 2; - case 18: if (p >= sieveEnd) { prime.setWheelIndex(18); break; } - *p &= BIT5; p += sievingPrime * 2 + 1; - case 19: if (p >= sieveEnd) { prime.setWheelIndex(19); break; } - *p &= BIT4; p += sievingPrime * 4 + 2; - case 20: if (p >= sieveEnd) { prime.setWheelIndex(20); break; } - *p &= BIT1; p += sievingPrime * 2 + 1; - case 21: if (p >= sieveEnd) { prime.setWheelIndex(21); break; } - *p &= BIT0; p += sievingPrime * 4 + 1; - case 22: if (p >= sieveEnd) { prime.setWheelIndex(22); break; } - *p &= BIT6; p += sievingPrime * 6 + 3; - case 23: if (p >= sieveEnd) { prime.setWheelIndex(23); break; } - *p &= BIT3; p += sievingPrime * 2 + 1; - } - break; - for (;;) // i*30 + 17 - { - case 24: for (; p < loopLimit; p += sievingPrime * 30 + 17) - { - p[sievingPrime * 0 + 0] &= BIT3; - p[sievingPrime * 6 + 3] &= BIT6; - p[sievingPrime * 10 + 6] &= BIT0; - p[sievingPrime * 12 + 7] &= BIT1; - p[sievingPrime * 16 + 9] &= BIT4; - p[sievingPrime * 18 + 10] &= BIT5; - p[sievingPrime * 22 + 12] &= BIT7; - p[sievingPrime * 28 + 16] &= BIT2; - } - if (p >= sieveEnd) { prime.setWheelIndex(24); break; } - *p &= BIT3; p += sievingPrime * 6 + 3; - case 25: if (p >= sieveEnd) { prime.setWheelIndex(25); break; } - *p &= BIT6; p += sievingPrime * 4 + 3; - case 26: if (p >= sieveEnd) { prime.setWheelIndex(26); break; } - *p &= BIT0; p += sievingPrime * 2 + 1; - case 27: if (p >= sieveEnd) { prime.setWheelIndex(27); break; } - *p &= BIT1; p += sievingPrime * 4 + 2; - case 28: if (p >= sieveEnd) { prime.setWheelIndex(28); break; } - *p &= BIT4; p += sievingPrime * 2 + 1; - case 29: if (p >= sieveEnd) { prime.setWheelIndex(29); break; } - *p &= BIT5; p += sievingPrime * 4 + 2; - case 30: if (p >= sieveEnd) { prime.setWheelIndex(30); break; } - *p &= BIT7; p += sievingPrime * 6 + 4; - case 31: if (p >= sieveEnd) { prime.setWheelIndex(31); break; } - *p &= BIT2; p += sievingPrime * 2 + 1; - } - break; - for (;;) // i*30 + 19 - { - case 32: for (; p < loopLimit; p += sievingPrime * 30 + 19) - { - p[sievingPrime * 0 + 0] &= BIT4; - p[sievingPrime * 6 + 4] &= BIT2; - p[sievingPrime * 10 + 6] &= BIT6; - p[sievingPrime * 12 + 8] &= BIT0; - p[sievingPrime * 16 + 10] &= BIT5; - p[sievingPrime * 18 + 11] &= BIT7; - p[sievingPrime * 22 + 14] &= BIT3; - p[sievingPrime * 28 + 18] &= BIT1; - } - if (p >= sieveEnd) { prime.setWheelIndex(32); break; } - *p &= BIT4; p += sievingPrime * 6 + 4; - case 33: if (p >= sieveEnd) { prime.setWheelIndex(33); break; } - *p &= BIT2; p += sievingPrime * 4 + 2; - case 34: if (p >= sieveEnd) { prime.setWheelIndex(34); break; } - *p &= BIT6; p += sievingPrime * 2 + 2; - case 35: if (p >= sieveEnd) { prime.setWheelIndex(35); break; } - *p &= BIT0; p += sievingPrime * 4 + 2; - case 36: if (p >= sieveEnd) { prime.setWheelIndex(36); break; } - *p &= BIT5; p += sievingPrime * 2 + 1; - case 37: if (p >= sieveEnd) { prime.setWheelIndex(37); break; } - *p &= BIT7; p += sievingPrime * 4 + 3; - case 38: if (p >= sieveEnd) { prime.setWheelIndex(38); break; } - *p &= BIT3; p += sievingPrime * 6 + 4; - case 39: if (p >= sieveEnd) { prime.setWheelIndex(39); break; } - *p &= BIT1; p += sievingPrime * 2 + 1; - } - break; - for (;;) // i*30 + 23 - { - case 40: for (; p < loopLimit; p += sievingPrime * 30 + 23) - { - p[sievingPrime * 0 + 0] &= BIT5; - p[sievingPrime * 6 + 5] &= BIT1; - p[sievingPrime * 10 + 8] &= BIT2; - p[sievingPrime * 12 + 9] &= BIT6; - p[sievingPrime * 16 + 12] &= BIT7; - p[sievingPrime * 18 + 14] &= BIT3; - p[sievingPrime * 22 + 17] &= BIT4; - p[sievingPrime * 28 + 22] &= BIT0; - } - if (p >= sieveEnd) { prime.setWheelIndex(40); break; } - *p &= BIT5; p += sievingPrime * 6 + 5; - case 41: if (p >= sieveEnd) { prime.setWheelIndex(41); break; } - *p &= BIT1; p += sievingPrime * 4 + 3; - case 42: if (p >= sieveEnd) { prime.setWheelIndex(42); break; } - *p &= BIT2; p += sievingPrime * 2 + 1; - case 43: if (p >= sieveEnd) { prime.setWheelIndex(43); break; } - *p &= BIT6; p += sievingPrime * 4 + 3; - case 44: if (p >= sieveEnd) { prime.setWheelIndex(44); break; } - *p &= BIT7; p += sievingPrime * 2 + 2; - case 45: if (p >= sieveEnd) { prime.setWheelIndex(45); break; } - *p &= BIT3; p += sievingPrime * 4 + 3; - case 46: if (p >= sieveEnd) { prime.setWheelIndex(46); break; } - *p &= BIT4; p += sievingPrime * 6 + 5; - case 47: if (p >= sieveEnd) { prime.setWheelIndex(47); break; } - *p &= BIT0; p += sievingPrime * 2 + 1; - } - break; - for (;;) // i*30 + 29 - { - case 48: for (; p < loopLimit; p += sievingPrime * 30 + 29) - { - p[sievingPrime * 0 + 0] &= BIT6; - p[sievingPrime * 6 + 6] &= BIT5; - p[sievingPrime * 10 + 10] &= BIT4; - p[sievingPrime * 12 + 12] &= BIT3; - p[sievingPrime * 16 + 16] &= BIT2; - p[sievingPrime * 18 + 18] &= BIT1; - p[sievingPrime * 22 + 22] &= BIT0; - p[sievingPrime * 28 + 27] &= BIT7; - } - if (p >= sieveEnd) { prime.setWheelIndex(48); break; } - *p &= BIT6; p += sievingPrime * 6 + 6; - case 49: if (p >= sieveEnd) { prime.setWheelIndex(49); break; } - *p &= BIT5; p += sievingPrime * 4 + 4; - case 50: if (p >= sieveEnd) { prime.setWheelIndex(50); break; } - *p &= BIT4; p += sievingPrime * 2 + 2; - case 51: if (p >= sieveEnd) { prime.setWheelIndex(51); break; } - *p &= BIT3; p += sievingPrime * 4 + 4; - case 52: if (p >= sieveEnd) { prime.setWheelIndex(52); break; } - *p &= BIT2; p += sievingPrime * 2 + 2; - case 53: if (p >= sieveEnd) { prime.setWheelIndex(53); break; } - *p &= BIT1; p += sievingPrime * 4 + 4; - case 54: if (p >= sieveEnd) { prime.setWheelIndex(54); break; } - *p &= BIT0; p += sievingPrime * 6 + 5; - case 55: if (p >= sieveEnd) { prime.setWheelIndex(55); break; } - *p &= BIT7; p += sievingPrime * 2 + 2; - } - break; - for (;;) // i*30 + 31 - { - case 56: for (; p < loopLimit; p += sievingPrime * 30 + 1) - { - p[sievingPrime * 0 + 0] &= BIT7; - p[sievingPrime * 6 + 1] &= BIT0; - p[sievingPrime * 10 + 1] &= BIT1; - p[sievingPrime * 12 + 1] &= BIT2; - p[sievingPrime * 16 + 1] &= BIT3; - p[sievingPrime * 18 + 1] &= BIT4; - p[sievingPrime * 22 + 1] &= BIT5; - p[sievingPrime * 28 + 1] &= BIT6; - } - if (p >= sieveEnd) { prime.setWheelIndex(56); break; } - *p &= BIT7; p += sievingPrime * 6 + 1; - case 57: if (p >= sieveEnd) { prime.setWheelIndex(57); break; } - *p &= BIT0; p += sievingPrime * 4 + 0; - case 58: if (p >= sieveEnd) { prime.setWheelIndex(58); break; } - *p &= BIT1; p += sievingPrime * 2 + 0; - case 59: if (p >= sieveEnd) { prime.setWheelIndex(59); break; } - *p &= BIT2; p += sievingPrime * 4 + 0; - case 60: if (p >= sieveEnd) { prime.setWheelIndex(60); break; } - *p &= BIT3; p += sievingPrime * 2 + 0; - case 61: if (p >= sieveEnd) { prime.setWheelIndex(61); break; } - *p &= BIT4; p += sievingPrime * 4 + 0; - case 62: if (p >= sieveEnd) { prime.setWheelIndex(62); break; } - *p &= BIT5; p += sievingPrime * 6 + 0; - case 63: if (p >= sieveEnd) { prime.setWheelIndex(63); break; } - *p &= BIT6; p += sievingPrime * 2 + 0; - } - break; - } - // set multipleIndex for next segment - prime.setMultipleIndex((uint64_t) (p - sieveEnd)); - } -} - -} // namespace diff -Nru primesieve-6.3+ds/src/primesieve/iterator-c.cpp primesieve-7.0+ds/src/primesieve/iterator-c.cpp --- primesieve-6.3+ds/src/primesieve/iterator-c.cpp 2017-11-18 12:38:21.000000000 +0000 +++ primesieve-7.0+ds/src/primesieve/iterator-c.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,161 +0,0 @@ -/// -/// @file iterator-c.cpp -/// @brief C port of primesieve::iterator. -/// -/// Copyright (C) 2017 Kim Walisch, -/// -/// This file is distributed under the BSD License. See the COPYING -/// file in the top level directory. -/// - -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -using namespace std; -using namespace primesieve; - -namespace { - -/// Convert pimpl pointer to vector -vector& to_vector(uint64_t* primes_pimpl) -{ - vector* primes = reinterpret_cast*>(primes_pimpl); - return *primes; -} - -/// Get a distance which ensures a good load balance -/// @n: Start or stop number -/// -uint64_t get_distance(uint64_t n, uint64_t& tiny_cache_size) -{ - n = max(n, 10); - uint64_t cache_size = config::MIN_CACHE_ITERATOR; - - if (tiny_cache_size < cache_size) - { - cache_size = tiny_cache_size; - tiny_cache_size *= 4; - } - - double x = (double) n; - double sqrtx = sqrt(x); - uint64_t primes = (uint64_t)(sqrtx / (log(sqrtx) - 1)); - uint64_t min_primes = cache_size / sizeof(uint64_t); - uint64_t max_primes = config::MAX_CACHE_ITERATOR / sizeof(uint64_t); - primes = inBetween(min_primes, primes, max_primes); - double distance = primes * log(x); - - return (uint64_t) distance; -} - -} - -/// C constructor -void primesieve_init(primesieve_iterator* it) -{ - it->primes_pimpl_ = reinterpret_cast(new vector()); - primesieve_skipto(it, 0, primesieve_get_max_stop()); -} - -/// C destructor -void primesieve_free_iterator(primesieve_iterator* it) -{ - if (it) - { - vector* primes = &to_vector(it->primes_pimpl_); - delete primes; - } -} - -void primesieve_skipto(primesieve_iterator* it, - uint64_t start, - uint64_t stop_hint) -{ - vector& primes = to_vector(it->primes_pimpl_); - primes.clear(); - it->start_ = start; - it->stop_ = start; - it->stop_hint_ = stop_hint; - it->i_ = 0; - it->last_idx_ = 0; - it->tiny_cache_size_ = 1 << 10; - it->is_error_ = false; -} - -void primesieve_generate_next_primes(primesieve_iterator* it) -{ - vector& primes = to_vector(it->primes_pimpl_); - - if (!it->is_error_) - { - try - { - primes.clear(); - - while (primes.empty()) - { - it->start_ = checkedAdd(it->stop_, 1); - it->stop_ = checkedAdd(it->start_, get_distance(it->start_, it->tiny_cache_size_)); - if (it->start_ <= it->stop_hint_ && it->stop_ >= it->stop_hint_) - it->stop_ = checkedAdd(it->stop_hint_, max_prime_gap(it->stop_hint_)); - generate_primes(it->start_, it->stop_, &primes); - if (primes.empty() && it->stop_ >= get_max_stop()) - throw primesieve_error("next_prime() > primesieve_get_max_stop()"); - } - } - catch (exception&) - { - primes.clear(); - primes.resize(64, PRIMESIEVE_ERROR); - it->is_error_ = true; - errno = EDOM; - } - } - - it->primes_ = &primes[0]; - it->last_idx_ = primes.size() - 1; - it->i_ = 0; -} - -void primesieve_generate_prev_primes(primesieve_iterator* it) -{ - vector& primes = to_vector(it->primes_pimpl_); - - if (!it->is_error_) - { - try - { - primes.clear(); - - while (primes.empty()) - { - it->stop_ = checkedSub(it->start_, 1); - it->start_ = checkedSub(it->stop_, get_distance(it->stop_, it->tiny_cache_size_)); - if (it->start_ <= it->stop_hint_ && it->stop_ >= it->stop_hint_) - it->start_ = checkedSub(it->stop_hint_, max_prime_gap(it->stop_hint_)); - if (it->start_ <= 2) - primes.push_back(0); - generate_primes(it->start_, it->stop_, &primes); - } - } - catch (exception&) - { - primes.clear(); - primes.resize(64, PRIMESIEVE_ERROR); - it->is_error_ = true; - errno = EDOM; - } - } - - it->primes_ = &primes[0]; - it->last_idx_ = primes.size() - 1; - it->i_ = it->last_idx_; -} diff -Nru primesieve-6.3+ds/src/primesieve/iterator.cpp primesieve-7.0+ds/src/primesieve/iterator.cpp --- primesieve-6.3+ds/src/primesieve/iterator.cpp 2017-11-18 12:38:21.000000000 +0000 +++ primesieve-7.0+ds/src/primesieve/iterator.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,102 +0,0 @@ -/// -/// @file iterator.cpp -/// -/// Copyright (C) 2017 Kim Walisch, -/// -/// This file is distributed under the BSD License. See the COPYING -/// file in the top level directory. -/// - -#include -#include -#include - -#include -#include -#include - -using namespace std; - -namespace primesieve { - -iterator::iterator(uint64_t start, uint64_t stop_hint) -{ - skipto(start, stop_hint); -} - -void iterator::skipto(uint64_t start, uint64_t stop_hint) -{ - start_ = start; - stop_ = start; - stop_hint_ = stop_hint; - i_ = 0; - last_idx_ = 0; - tiny_cache_size_ = 1 << 10; - primes_.clear(); -} - -void iterator::generate_next_primes() -{ - primes_.clear(); - - while (primes_.empty()) - { - start_ = checkedAdd(stop_, 1); - stop_ = checkedAdd(start_, get_distance(start_)); - if (start_ <= stop_hint_ && stop_ >= stop_hint_) - stop_ = checkedAdd(stop_hint_, max_prime_gap(stop_hint_)); - generate_primes(start_, stop_, &primes_); - if (primes_.empty() && - stop_ >= get_max_stop()) - throw primesieve_error("next_prime() > 2^64"); - } - - last_idx_ = primes_.size() - 1; - i_ = 0; -} - -void iterator::generate_prev_primes() -{ - primes_.clear(); - - while (primes_.empty()) - { - stop_ = checkedSub(start_, 1); - start_ = checkedSub(stop_, get_distance(stop_)); - if (start_ <= stop_hint_ && stop_ >= stop_hint_) - start_ = checkedSub(stop_hint_, max_prime_gap(stop_hint_)); - if (start_ <= 2) - primes_.push_back(0); - generate_primes(start_, stop_, &primes_); - } - - last_idx_ = primes_.size() - 1; - i_ = last_idx_; -} - -/// Get a distance which ensures a good load balance -/// @n: Start or stop number -/// -uint64_t iterator::get_distance(uint64_t n) -{ - n = max(n, 10); - uint64_t cache_size = config::MIN_CACHE_ITERATOR; - - if (tiny_cache_size_ < cache_size) - { - cache_size = tiny_cache_size_; - tiny_cache_size_ *= 4; - } - - double x = (double) n; - double sqrtx = sqrt(x); - uint64_t primes = (uint64_t)(sqrtx / (log(sqrtx) - 1)); - uint64_t min_primes = cache_size / sizeof(uint64_t); - uint64_t max_primes = config::MAX_CACHE_ITERATOR / sizeof(uint64_t); - primes = inBetween(min_primes, primes, max_primes); - double distance = primes * log(x); - - return (uint64_t) distance; -} - -} // namespace diff -Nru primesieve-6.3+ds/src/primesieve/nthPrime.cpp primesieve-7.0+ds/src/primesieve/nthPrime.cpp --- primesieve-6.3+ds/src/primesieve/nthPrime.cpp 2017-11-18 12:38:21.000000000 +0000 +++ primesieve-7.0+ds/src/primesieve/nthPrime.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,175 +0,0 @@ -/// -/// @file nthPrime.cpp -/// -/// Copyright (C) 2017 Kim Walisch, -/// -/// This file is distributed under the BSD License. See the COPYING -/// file in the top level directory. -/// - -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -using namespace std; -using namespace primesieve; - -namespace { - -void checkLimit(uint64_t start) -{ - if (start >= get_max_stop()) - throw primesieve_error("nth prime > 2^64"); -} - -void checkLowerLimit(uint64_t stop) -{ - if (stop == 0) - throw primesieve_error("nth prime < 2 is impossible"); -} - -bool sieveBackwards(int64_t n, int64_t count, uint64_t stop) -{ - return (count >= n) && - !(count == n && stop < 2); -} - -// Prime count approximation -int64_t pix(int64_t n) -{ - double x = (double) n; - x = max(4.0, x); - double pix = x / log(x); - return (int64_t) pix; -} - -uint64_t nthPrimeDist(int64_t n, int64_t count, uint64_t start) -{ - double x = (double) (n - count); - - x = abs(x); - x = max(x, 4.0); - - // rough pi(x) approximation - double logx = log(x); - double loglogx = log(logx); - double pix = x * (logx + loglogx - 1); - - // correct start if sieving backwards to - // get more accurate approximation - if (count >= n) - { - double st = start - pix; - st = max(0.0, st); - start = (uint64_t) st; - } - - // approximate the nth prime using: - // start + n * log(start + pi(n) / loglog(n)) - double startPix = start + pix / loglogx; - startPix = max(4.0, startPix); - double logStartPix = log(startPix); - double dist = max(pix, x * logStartPix); - - // ensure start + dist <= nth prime - if (count < n) - dist -= sqrt(dist) * log(logStartPix) * 2; - // ensure start + dist >= nth prime - if (count > n) - dist += sqrt(dist) * log(logStartPix) * 2; - - // if n is very small: - // ensure start + dist >= nth prime - double maxPrimeGap = max_prime_gap(startPix); - dist = max(dist, maxPrimeGap); - - return (uint64_t) dist; -} - -} // namespace - -namespace primesieve { - -uint64_t PrimeSieve::nthPrime(uint64_t n) -{ - return nthPrime(0, n); -} - -uint64_t PrimeSieve::nthPrime(int64_t n, uint64_t start) -{ - setStart(start); - auto t1 = chrono::system_clock::now(); - - if (n == 0) - n = 1; // like Mathematica - else if (n > 0) - start = checkedAdd(start, 1); - else if (n < 0) - start = checkedSub(start, 1); - - uint64_t stop = start; - uint64_t dist = nthPrimeDist(n, 0, start); - uint64_t nthPrimeGuess = checkedAdd(start, dist); - - int64_t count = 0; - int64_t tinyN = 100000; - tinyN = max(tinyN, pix(isqrt(nthPrimeGuess))); - - while ((n - count) > tinyN || - sieveBackwards(n, count, stop)) - { - if (count < n) - { - checkLimit(start); - dist = nthPrimeDist(n, count, start); - stop = checkedAdd(start, dist); - count += countPrimes(start, stop); - start = checkedAdd(stop, 1); - } - if (sieveBackwards(n, count, stop)) - { - checkLowerLimit(stop); - dist = nthPrimeDist(n, count, stop); - start = checkedSub(start, dist); - count -= (int64_t) countPrimes(start, stop); - stop = checkedSub(start, 1); - } - } - - if (n < 0) - count -= 1; - - // here start < nth prime, - // hence we can sieve forward the remaining - // distance and find the nth prime - assert(count < n); - - try - { - checkLimit(start); - dist = nthPrimeDist(n, count, start) * 2; - start = checkedSub(start, 1); - stop = checkedAdd(start, dist); - uint64_t prime = 0; - for (primesieve::iterator it(start, stop); count < n; count++) - prime = it.next_prime(); - - auto t2 = chrono::system_clock::now(); - chrono::duration seconds = t2 - t1; - seconds_ = seconds.count(); - - return prime; - } - catch (primesieve_error&) { } - - throw primesieve_error("nth prime > 2^64"); -} - -} // namespace diff -Nru primesieve-6.3+ds/src/primesieve/ParallelPrimeSieve.cpp primesieve-7.0+ds/src/primesieve/ParallelPrimeSieve.cpp --- primesieve-6.3+ds/src/primesieve/ParallelPrimeSieve.cpp 2017-11-18 12:38:21.000000000 +0000 +++ primesieve-7.0+ds/src/primesieve/ParallelPrimeSieve.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,212 +0,0 @@ -/// -/// @file ParallelPrimeSieve.cpp -/// @brief Multi-threaded prime sieve using std::async. -/// -/// Copyright (C) 2017 Kim Walisch, -/// -/// This file is distributed under the BSD License. See the COPYING -/// file in the top level directory. -/// - -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -using namespace std; - -namespace { - -template -vector& operator+=(vector& v1, const vector& v2) -{ - assert(v1.size() == v2.size()); - for (size_t i = 0; i < v1.size(); i++) - v1[i] += v2[i]; - return v1; -} - -} // namespace - -namespace primesieve { - -ParallelPrimeSieve::ParallelPrimeSieve() : - shm_(nullptr), - numThreads_(getMaxThreads()) -{ } - -void ParallelPrimeSieve::init(SharedMemory& shm) -{ - setStart(shm.start); - setStop(shm.stop); - setSieveSize(shm.sieveSize); - setFlags(shm.flags); - setNumThreads(shm.threads); - shm_ = &shm; -} - -int ParallelPrimeSieve::getMaxThreads() -{ - return max(1, thread::hardware_concurrency()); -} - -int ParallelPrimeSieve::getNumThreads() const -{ - return numThreads_; -} - -void ParallelPrimeSieve::setNumThreads(int threads) -{ - numThreads_ = inBetween(1, threads, getMaxThreads()); -} - -/// Get an ideal number of threads for -/// the start_ and stop_ numbers -/// -int ParallelPrimeSieve::idealNumThreads() const -{ - if (start_ > stop_) - return 1; - - uint64_t threshold = isqrt(stop_) / 5; - threshold = max(threshold, config::MIN_THREAD_DISTANCE); - uint64_t threads = getDistance() / threshold; - threads = inBetween(1, threads, numThreads_); - - return (int) threads; -} - -/// Get a thread distance which ensures a good load -/// balance when using multiple threads -/// -uint64_t ParallelPrimeSieve::getThreadDistance(int threads) const -{ - assert(threads > 0); - - uint64_t balanced = isqrt(stop_) * 1000; - uint64_t unbalanced = getDistance() / threads; - uint64_t fastest = min(balanced, unbalanced); - uint64_t threadDistance = max(config::MIN_THREAD_DISTANCE, fastest); - uint64_t iters = getDistance() / threadDistance; - - if (iters < threads * 5u) - threadDistance = max(config::MIN_THREAD_DISTANCE, unbalanced); - - threadDistance += 30 - threadDistance % 30; - return threadDistance; -} - -/// Align n to modulo (30 + 2) to prevent prime k-tuplet -/// (twin primes, prime triplets) gaps -/// -uint64_t ParallelPrimeSieve::align(uint64_t n) const -{ - uint64_t n32 = checkedAdd(n, 32); - if (n32 >= stop_) - return stop_; - - return n32 - n % 30; -} - -/// Sieve the primes and prime k-tuplets in [start_, stop_] -/// in parallel using multi-threading -/// -void ParallelPrimeSieve::sieve() -{ - reset(); - - if (start_ > stop_) - return; - - int threads = idealNumThreads(); - - if (threads == 1) - PrimeSieve::sieve(); - else - { - auto t1 = chrono::system_clock::now(); - uint64_t threadDistance = getThreadDistance(threads); - uint64_t iters = ((getDistance() - 1) / threadDistance) + 1; - threads = inBetween(1, threads, iters); - atomic i(0); - - // each thread executes 1 task - auto task = [&]() - { - PrimeSieve ps(this); - counts_t counts(counts_.size(), 0); - uint64_t j; - - while ((j = i++) < iters) - { - uint64_t start = start_ + j * threadDistance; - uint64_t stop = checkedAdd(start, threadDistance); - stop = align(stop); - if (start > start_) - start = align(start) + 1; - - // sieve the range [start, stop] - ps.sieve(start, stop); - counts += ps.getCounts(); - } - - return counts; - }; - - vector> futures; - futures.reserve(threads); - - for (int t = 0; t < threads; t++) - futures.emplace_back(async(launch::async, task)); - - for (auto &f : futures) - counts_ += f.get(); - - auto t2 = chrono::system_clock::now(); - chrono::duration seconds = t2 - t1; - seconds_ = seconds.count(); - } - - if (shm_) - { - // communicate the sieving results to - // the primesieve GUI application - copy(counts_.begin(), counts_.end(), shm_->counts); - shm_->seconds = seconds_; - } -} - -/// Print status in percent to stdout -/// @processed: Sum of recently processed segments -/// @tryLock: Do not block if tryLock = true -/// -bool ParallelPrimeSieve::updateStatus(uint64_t processed, bool tryLock) -{ - unique_lock lock(lock_, defer_lock); - - if (tryLock) - lock.try_lock(); - else - lock.lock(); - - if (lock.owns_lock()) - { - PrimeSieve::updateStatus(processed); - if (shm_) - shm_->status = getStatus(); - return true; - } - - return false; -} - -} // namespace diff -Nru primesieve-6.3+ds/src/primesieve/popcount.cpp primesieve-7.0+ds/src/primesieve/popcount.cpp --- primesieve-6.3+ds/src/primesieve/popcount.cpp 2017-11-18 12:38:21.000000000 +0000 +++ primesieve-7.0+ds/src/primesieve/popcount.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,95 +0,0 @@ -/// -/// @file popcount.cpp -/// @brief Fast algorithm to count the number of 1 bits in an -/// array using only integer operations. -/// -/// Copyright (C) 2017 Kim Walisch, -/// -/// This file is distributed under the BSD License. See the COPYING -/// file in the top level directory. -/// - -#include - -namespace { - -/// This uses fewer arithmetic operations than any other known -/// implementation on machines with fast multiplication. -/// It uses 12 arithmetic operations, one of which is a multiply. -/// http://en.wikipedia.org/wiki/Hamming_weight#Efficient_implementation -/// -uint64_t popcount64(uint64_t x) -{ - const uint64_t m1 = 0x5555555555555555ull; - const uint64_t m2 = 0x3333333333333333ull; - const uint64_t m4 = 0x0F0F0F0F0F0F0F0Full; - const uint64_t h01 = 0x0101010101010101ull; - - x -= (x >> 1) & m1; - x = (x & m2) + ((x >> 2) & m2); - x = (x + (x >> 4)) & m4; - return (x * h01) >> 56; -} - -/// Carry-save adder (CSA). -/// @see Chapter 5 in "Hacker's Delight". -/// -void CSA(uint64_t& h, uint64_t& l, uint64_t a, uint64_t b, uint64_t c) -{ - uint64_t u = a ^ b; - h = (a & b) | (u & c); - l = u ^ c; -} - -} // namespace - -namespace primesieve { - -/// Harley-Seal popcount (4th iteration). -/// The Harley-Seal popcount algorithm is one of the fastest algorithms -/// for counting 1 bits in an array using only integer operations. -/// This implementation uses only 5.69 instructions per 64-bit word. -/// @see Chapter 5 in "Hacker's Delight" 2nd edition. -/// -uint64_t popcount(const uint64_t* array, uint64_t size) -{ - uint64_t total = 0; - uint64_t ones = 0, twos = 0, fours = 0, eights = 0, sixteens = 0; - uint64_t twosA, twosB, foursA, foursB, eightsA, eightsB; - uint64_t limit = size - size % 16; - uint64_t i = 0; - - for(; i < limit; i += 16) - { - CSA(twosA, ones, ones, array[i+0], array[i+1]); - CSA(twosB, ones, ones, array[i+2], array[i+3]); - CSA(foursA, twos, twos, twosA, twosB); - CSA(twosA, ones, ones, array[i+4], array[i+5]); - CSA(twosB, ones, ones, array[i+6], array[i+7]); - CSA(foursB, twos, twos, twosA, twosB); - CSA(eightsA,fours, fours, foursA, foursB); - CSA(twosA, ones, ones, array[i+8], array[i+9]); - CSA(twosB, ones, ones, array[i+10], array[i+11]); - CSA(foursA, twos, twos, twosA, twosB); - CSA(twosA, ones, ones, array[i+12], array[i+13]); - CSA(twosB, ones, ones, array[i+14], array[i+15]); - CSA(foursB, twos, twos, twosA, twosB); - CSA(eightsB, fours, fours, foursA, foursB); - CSA(sixteens, eights, eights, eightsA, eightsB); - - total += popcount64(sixteens); - } - - total *= 16; - total += 8 * popcount64(eights); - total += 4 * popcount64(fours); - total += 2 * popcount64(twos); - total += 1 * popcount64(ones); - - for(; i < size; i++) - total += popcount64(array[i]); - - return total; -} - -} // namespace diff -Nru primesieve-6.3+ds/src/primesieve/PreSieve.cpp primesieve-7.0+ds/src/primesieve/PreSieve.cpp --- primesieve-6.3+ds/src/primesieve/PreSieve.cpp 2017-11-18 12:38:21.000000000 +0000 +++ primesieve-7.0+ds/src/primesieve/PreSieve.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,97 +0,0 @@ -/// -/// @file PreSieve.cpp -/// @brief Pre-sieve multiples of small primes to speed up the -/// sieve of Eratosthenes. -/// -/// Copyright (C) 2017 Kim Walisch, -/// -/// This file is distributed under the BSD License. See the COPYING -/// file in the top level directory. -/// - -#include -#include -#include -#include - -#include -#include -#include -#include - -using namespace std; -using namespace primesieve; - -namespace { - -const uint64_t primes[] = { 2, 3, 5, 7, 11, 13, 17, 19, 23 }; - -const uint64_t primeProduct[] = { 2, 6, 30, 210, 2310, 30030, 510510, 9699690, 223092870 }; - -} // namespace - -namespace primesieve { - -PreSieve::PreSieve(uint64_t start, uint64_t stop) : - maxPrime_(7), - buffer_(nullptr) -{ - // use a small buffer_ array if the - // sieve interval is small - uint64_t distance = stop - start; - uint64_t threshold = max(isqrt(stop), distance) / 10; - - for (int i = 4; i < 8; i++) - if (threshold > primeProduct[i]) - maxPrime_ = primes[i]; - - for (int i = 0; primes[i] <= maxPrime_; i++) - primeProduct_ = primeProduct[i]; - - init(); -} - -void PreSieve::init() -{ - size_ = primeProduct_ / NUMBERS_PER_BYTE; - deleter_.reset(new byte_t[size_]); - buffer_ = deleter_.get(); - memset(buffer_, 0xff, size_); - - uint64_t stop = primeProduct_ * 2; - EratSmall eratSmall(stop, size_, maxPrime_); - - for (int i = 3; primes[i] <= maxPrime_; i++) - eratSmall.addSievingPrime(primes[i], primeProduct_); - - // pre-sieve [primeProduct, primeProduct * 2] - eratSmall.crossOff(buffer_, size_); -} - -/// Pre-sieve multiples of small primes -void PreSieve::copy(byte_t* sieve, - uint64_t sieveSize, - uint64_t segmentLow) const -{ - // find segmentLow index - uint64_t remainder = segmentLow % primeProduct_; - uint64_t index = remainder / NUMBERS_PER_BYTE; - uint64_t sizeLeft = size_ - index; - - if (sieveSize <= sizeLeft) - memcpy(sieve, &buffer_[index], sieveSize); - else - { - // copy the last remaining bytes at the end of buffer - // to the beginning of the sieve array - memcpy(sieve, &buffer_[index], sizeLeft); - - // restart copying at the beginning of buffer - for (index = sizeLeft; index + size_ < sieveSize; index += size_) - memcpy(&sieve[index], buffer_, size_); - - memcpy(&sieve[index], buffer_, sieveSize - index); - } -} - -} // namespace diff -Nru primesieve-6.3+ds/src/primesieve/PrimeGenerator.cpp primesieve-7.0+ds/src/primesieve/PrimeGenerator.cpp --- primesieve-6.3+ds/src/primesieve/PrimeGenerator.cpp 2017-11-18 12:38:21.000000000 +0000 +++ primesieve-7.0+ds/src/primesieve/PrimeGenerator.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,184 +0,0 @@ -/// -/// @file PrimeGenerator.cpp -/// @brief After a segment has been sieved PrimeGenerator is -/// used to reconstruct primes and prime k-tuplets from -/// 1 bits of the sieve array. -/// -/// Copyright (C) 2017 Kim Walisch, -/// -/// This file is distributed under the BSD License. See the COPYING -/// file in the top level directory. -/// - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -using namespace std; - -namespace primesieve { - -/// popcount.cpp -uint64_t popcount(const uint64_t* array, uint64_t size); - -const uint64_t PrimeGenerator::bitmasks_[6][5] = -{ - { END }, - { 0x06, 0x18, 0xc0, END }, // Twin primes: b00000110, b00011000, b11000000 - { 0x07, 0x0e, 0x1c, 0x38, END }, // Prime triplets: b00000111, b00001110, ... - { 0x1e, END }, // Prime quadruplets: b00011110 - { 0x1f, 0x3e, END }, // Prime quintuplets - { 0x3f, END } // Prime sextuplets -}; - -PrimeGenerator::PrimeGenerator(PrimeSieve& ps, const PreSieve& preSieve) : - SieveOfEratosthenes(max(7, ps.getStart()), - ps.getStop(), - ps.getSieveSize(), - preSieve), - ps_(ps), - counts_(ps_.getCounts()) -{ - if (ps_.isFlag(ps_.COUNT_TWINS, ps_.COUNT_SEXTUPLETS)) - init_kCounts(); -} - -/// Calculate the number of twins, triplets, ... -/// for each possible byte value -/// -void PrimeGenerator::init_kCounts() -{ - for (uint_t i = 1; i < counts_.size(); i++) - { - if (ps_.isCount(i)) - { - kCounts_[i].resize(256); - - for (uint64_t j = 0; j < 256; j++) - { - byte_t count = 0; - for (const uint64_t* b = bitmasks_[i]; *b <= j; b++) - { - if ((j & *b) == *b) - count++; - } - kCounts_[i][j] = count; - } - } - } -} - -/// Executed after each sieved segment. -/// @see sieveSegment() in SieveOfEratosthenes.cpp -/// -void PrimeGenerator::generatePrimes(const byte_t* sieve, uint64_t sieveSize) -{ - if (ps_.isStore()) - storePrimes(ps_.getStore(), sieve, sieveSize); - if (ps_.isCount()) - count(sieve, sieveSize); - if (ps_.isPrint()) - print(sieve, sieveSize); - if (ps_.isStatus()) - ps_.updateStatus(sieveSize * NUMBERS_PER_BYTE); -} - -void PrimeGenerator::storePrimes(Store& store, const byte_t* sieve, uint64_t sieveSize) const -{ - uint64_t low = getSegmentLow(); - - for (uint64_t i = 0; i < sieveSize; i += 8) - { - uint64_t bits = littleendian_cast(&sieve[i]); - while (bits) - store(nextPrime(&bits, low)); - - low += NUMBERS_PER_BYTE * 8; - } -} - -/// Count the primes and prime k-tuplets -/// in the current segment -/// -void PrimeGenerator::count(const byte_t* sieve, uint64_t sieveSize) -{ - if (ps_.isFlag(ps_.COUNT_PRIMES)) - counts_[0] += popcount((const uint64_t*) sieve, ceilDiv(sieveSize, 8)); - - // i = 1 twins, i = 2 triplets, ... - for (uint_t i = 1; i < counts_.size(); i++) - { - if (ps_.isCount(i)) - { - uint64_t sum = 0; - - for (uint64_t j = 0; j < sieveSize; j += 4) - { - sum += kCounts_[i][sieve[j+0]]; - sum += kCounts_[i][sieve[j+1]]; - sum += kCounts_[i][sieve[j+2]]; - sum += kCounts_[i][sieve[j+3]]; - } - - counts_[i] += sum; - } - } -} - -/// Print primes and prime k-tuplets to cout. -/// primes <= 5 are handled in processSmallPrimes(). -/// -void PrimeGenerator::print(const byte_t* sieve, uint64_t sieveSize) const -{ - if (ps_.isFlag(ps_.PRINT_PRIMES)) - { - uint64_t low = getSegmentLow(); - - for (uint64_t i = 0; i < sieveSize; i += 8) - { - uint64_t bits = littleendian_cast(&sieve[i]); - while (bits) - cout << nextPrime(&bits, low) << '\n'; - - low += NUMBERS_PER_BYTE * 8; - } - } - - // print prime k-tuplets - if (ps_.isFlag(ps_.PRINT_TWINS, ps_.PRINT_SEXTUPLETS)) - { - uint_t i = 1; // i = 1 twins, i = 2 triplets, ... - uint64_t low = getSegmentLow(); - - for (; !ps_.isPrint(i); i++); - for (uint64_t j = 0; j < sieveSize; j++, low += NUMBERS_PER_BYTE) - { - for (const uint64_t* bitmask = bitmasks_[i]; *bitmask <= sieve[j]; bitmask++) - { - if ((sieve[j] & *bitmask) == *bitmask) - { - ostringstream kTuplet; - kTuplet << "("; - uint64_t bits = *bitmask; - while (bits != 0) - { - kTuplet << nextPrime(&bits, low); - kTuplet << ((bits != 0) ? ", " : ")\n"); - } - cout << kTuplet.str(); - } - } - } - } -} - -} // namespace diff -Nru primesieve-6.3+ds/src/primesieve/PrimeSieve.cpp primesieve-7.0+ds/src/primesieve/PrimeSieve.cpp --- primesieve-6.3+ds/src/primesieve/PrimeSieve.cpp 2017-11-18 12:38:21.000000000 +0000 +++ primesieve-7.0+ds/src/primesieve/PrimeSieve.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,350 +0,0 @@ -/// -/// @file PrimeSieve.hpp -/// @brief The PrimeSieve class is a high level class that -/// manages prime sieving using the PreSieve, SievingPrimes -/// and PrimeGenerator classes. -/// -/// Copyright (C) 2017 Kim Walisch, -/// -/// This file is distributed under the BSD License. See the COPYING -/// file in the top level directory. -/// - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -using namespace std; - -namespace { - -struct SmallPrime -{ - uint64_t first; - uint64_t last; - int index; - string str; -}; - -const array smallPrimes -{{ - { 2, 2, 0, "2" }, - { 3, 3, 0, "3" }, - { 5, 5, 0, "5" }, - { 3, 5, 1, "(3, 5)" }, - { 5, 7, 1, "(5, 7)" }, - { 5, 11, 2, "(5, 7, 11)" }, - { 5, 13, 3, "(5, 7, 11, 13)" }, - { 5, 17, 4, "(5, 7, 11, 13, 17)" } -}}; - -} // namespace - -namespace primesieve { - -int get_sieve_size(); - -PrimeSieve::PrimeSieve() : - start_(0), - stop_(0), - counts_(6), - flags_(COUNT_PRIMES), - parent_(nullptr), - store_(nullptr) -{ - setSieveSize(get_sieve_size()); - reset(); -} - -/// ParallelPrimeSieve creates one PrimeSieve -/// child object for each thread. -/// -PrimeSieve::PrimeSieve(PrimeSieve* parent) : - counts_(6), - sieveSize_(parent->sieveSize_), - flags_(parent->flags_), - parent_(parent), - store_(parent->store_) -{ } - -PrimeSieve::~PrimeSieve() -{ } - -void PrimeSieve::reset() -{ - fill(counts_.begin(), counts_.end(), 0); - seconds_ = 0.0; - toUpdate_ = 0; - processed_ = 0; - percent_ = -1.0; -} - -uint64_t PrimeSieve::getStart() const { return start_; } -uint64_t PrimeSieve::getStop() const { return stop_; } -uint64_t PrimeSieve::getDistance() const { return stop_ - start_; } -uint64_t PrimeSieve::getPrimeCount() const { return counts_[0]; } -uint64_t PrimeSieve::getTwinCount() const { return counts_[1]; } -uint64_t PrimeSieve::getTripletCount() const { return counts_[2]; } -uint64_t PrimeSieve::getQuadrupletCount() const { return counts_[3]; } -uint64_t PrimeSieve::getQuintupletCount() const { return counts_[4]; } -uint64_t PrimeSieve::getSextupletCount() const { return counts_[5]; } -uint64_t PrimeSieve::getCount(int index) const { return counts_.at(index); } -double PrimeSieve::getStatus() const { return percent_; } -double PrimeSieve::getSeconds() const { return seconds_; } -int PrimeSieve::getSieveSize() const { return sieveSize_; } -bool PrimeSieve::isFlag(int flag) const { return (flags_ & flag) == flag; } -bool PrimeSieve::isFlag(int first, int last) const { return (flags_ & (last * 2 - first)) != 0; } -bool PrimeSieve::isCount(int index) const { return isFlag(COUNT_PRIMES << index); } -bool PrimeSieve::isPrint(int index) const { return isFlag(PRINT_PRIMES << index); } -bool PrimeSieve::isCount() const { return isFlag(COUNT_PRIMES, COUNT_SEXTUPLETS); } -bool PrimeSieve::isPrint() const { return isFlag(PRINT_PRIMES, PRINT_SEXTUPLETS); } -bool PrimeSieve::isStatus() const { return isFlag(PRINT_STATUS, CALCULATE_STATUS); } -bool PrimeSieve::isStore() const { return store_ != nullptr; } -bool PrimeSieve::isParallelPrimeSieve() const { return parent_ != nullptr; } - -/// Set a start number (lower bound) for sieving -void PrimeSieve::setStart(uint64_t start) -{ - start_ = start; -} - -/// Set a stop number (upper bound) for sieving -void PrimeSieve::setStop(uint64_t stop) -{ - stop_ = stop; -} - -/// Set the size of the sieve array in kilobytes. -/// The best sieving performance is usually achieved if the -/// sieve size is set to the CPU's L1 or L2 cache size. -/// -void PrimeSieve::setSieveSize(int sieveSize) -{ - sieveSize_ = inBetween(8, sieveSize, 4096); - sieveSize_ = floorPow2(sieveSize_); -} - -Store& PrimeSieve::getStore() -{ - return *store_; -} - -PrimeSieve::counts_t& PrimeSieve::getCounts() -{ - return counts_; -} - -void PrimeSieve::setFlags(int flags) -{ - flags_ = flags; -} - -void PrimeSieve::addFlags(int flags) -{ - flags_ |= flags; -} - -/// Print status in percent to stdout. -/// @processed: Sum of recently processed segments -/// -bool PrimeSieve::updateStatus(uint64_t processed, bool tryLock) -{ - if (isParallelPrimeSieve()) - { - toUpdate_ += processed; - if (parent_->updateStatus(toUpdate_, tryLock)) - toUpdate_ = 0; - } - else - { - processed_ += processed; - double percent = 100; - if (getDistance() > 0) - percent = processed_ * 100.0 / getDistance(); - double old = percent_; - percent_ = min(percent, 100.0); - if (isFlag(PRINT_STATUS)) - printStatus(old, percent_); - } - return true; -} - -void PrimeSieve::printStatus(double old, double current) -{ - int percent = (int) current; - if (percent > (int) old) - { - cout << '\r' << percent << '%' << flush; - if (percent == 100) - cout << endl; - } -} - -/// Process small primes <= 5 and small k-tuplets <= 17 -void PrimeSieve::processSmallPrimes() -{ - for (auto& p : smallPrimes) - { - if (p.first >= start_ && p.last <= stop_) - { - if (isCount(p.index)) - counts_[p.index]++; - if (isPrint(p.index)) - cout << p.str << '\n'; - if (isStore() && p.index == 0) - (*store_)(p.first); - } - } -} - -/// Sieve the primes and prime k-tuplets (twin primes, -/// prime triplets, ...) in [start, stop] -/// -void PrimeSieve::sieve() -{ - reset(); - - if (start_ > stop_) - return; - - auto t1 = chrono::system_clock::now(); - int initStatus = 0; - int finishStatus = 10; - - if (isStatus()) - updateStatus(initStatus); - - if (start_ <= 5) - processSmallPrimes(); - - if (stop_ >= 7) - { - PreSieve preSieve(start_, stop_); - PrimeGenerator primeGen(*this, preSieve); - - // generate sieving primes for primeGen - if (primeGen.getSqrtStop() > preSieve.getMaxPrime()) - { - SievingPrimes sp(primeGen, preSieve); - sp.generate(); - } - - // sieve [start, stop] - primeGen.sieve(); - } - - auto t2 = chrono::system_clock::now(); - chrono::duration seconds = t2 - t1; - seconds_ = seconds.count(); - - if (isStatus()) - updateStatus(finishStatus, false); -} - -void PrimeSieve::sieve(uint64_t start, uint64_t stop) -{ - setStart(start); - setStop(stop); - sieve(); -} - -void PrimeSieve::sieve(uint64_t start, uint64_t stop, int flags) -{ - setStart(start); - setStop(stop); - setFlags(flags); - sieve(); -} - -void PrimeSieve::storePrimes(uint64_t start, uint64_t stop, Store* store) -{ - if (!store) - throw primesieve_error("invalid store pointer"); - store_ = store; - flags_ = 0; - sieve(start, stop); -} - -// Print methods - -void PrimeSieve::printPrimes(uint64_t start, uint64_t stop) -{ - sieve(start, stop, PRINT_PRIMES); -} - -void PrimeSieve::printTwins(uint64_t start, uint64_t stop) -{ - sieve(start, stop, PRINT_TWINS); -} - -void PrimeSieve::printTriplets(uint64_t start, uint64_t stop) -{ - sieve(start, stop, PRINT_TRIPLETS); -} - -void PrimeSieve::printQuadruplets(uint64_t start, uint64_t stop) -{ - sieve(start, stop, PRINT_QUADRUPLETS); -} - -void PrimeSieve::printQuintuplets(uint64_t start, uint64_t stop) -{ - sieve(start, stop, PRINT_QUINTUPLETS); -} - -void PrimeSieve::printSextuplets(uint64_t start, uint64_t stop) -{ - sieve(start, stop, PRINT_SEXTUPLETS); -} - -// Count methods - -uint64_t PrimeSieve::countPrimes(uint64_t start, uint64_t stop) -{ - sieve(start, stop, COUNT_PRIMES); - return getPrimeCount(); -} - -uint64_t PrimeSieve::countTwins(uint64_t start, uint64_t stop) -{ - sieve(start, stop, COUNT_TWINS); - return getTwinCount(); -} - -uint64_t PrimeSieve::countTriplets(uint64_t start, uint64_t stop) -{ - sieve(start, stop, COUNT_TRIPLETS); - return getTripletCount(); -} - -uint64_t PrimeSieve::countQuadruplets(uint64_t start, uint64_t stop) -{ - sieve(start, stop, COUNT_QUADRUPLETS); - return getQuadrupletCount(); -} - -uint64_t PrimeSieve::countQuintuplets(uint64_t start, uint64_t stop) -{ - sieve(start, stop, COUNT_QUINTUPLETS); - return getQuintupletCount(); -} - -uint64_t PrimeSieve::countSextuplets(uint64_t start, uint64_t stop) -{ - sieve(start, stop, COUNT_SEXTUPLETS); - return getSextupletCount(); -} - -} // namespace diff -Nru primesieve-6.3+ds/src/primesieve/README primesieve-7.0+ds/src/primesieve/README --- primesieve-6.3+ds/src/primesieve/README 2017-11-18 12:38:21.000000000 +0000 +++ primesieve-7.0+ds/src/primesieve/README 1970-01-01 00:00:00.000000000 +0000 @@ -1,141 +0,0 @@ -About -===== - -This directory (src/primesieve) contains primesieve's sieve of -Eratosthenes implementation. Most files that start with a capital -letter contain a class of the same name. The header files of these -classes are stored in include/primesive. Below is a short explanation -of the most important classes and files. - -C++ classes ------------ -* PrimeSieve - PrimeSieve objects provide an easy API for prime sieving, - PrimeSieve::sieve(start, stop) sieves the primes within the - interval [start, stop]. The classes below are all used directly or - indirectly for sieving. - -* ParallelPrimeSieve (derived from PrimeSieve) - ParallelPrimeSieve launches multiple threads using std::async and - each thread sieves a part of the range [start, stop] using a - PrimeSieve object. At the end all partial results are combined to - get the final result. - -* SieveOfEratosthenes (abstract class) - Implementation of the segmented sieve of Eratosthenes using a bit - array with 30 numbers per byte, each byte of the sieve array holds - the 8 offsets k = { 7, 11, 13, 17, 19, 23, 29, 31 }. - Its main methods are addSievingPrime(uint64_t) which is called - consecutively for all primes <= sqrt(n) and sieve() which sieves - the primes in [start, stop]. SieveOfEratosthenes uses the - EratSmall, EratMedium and EratBig classes to cross-off multiples. - -* PrimeGenerator (derived from SieveOfEratosthenes) - After a segment has been sieved (using SieveOfEratosthenes) - PrimeGenerator is used to reconstruct primes and prime k-tuplets - from 1 bits of the sieve array. - -* SievingPrimes (derived from SieveOfEratosthenes) - Generates the sieving primes <= sqrt(stop) for PrimeGenerator. - -* PreSieve - Pre-sieve multiples of small primes e.g. <= 19 to speed up the - sieve of Eratosthenes. Upon creation the multiples of small primes - are removed from a buffer. Later this buffer is simply copied to the - sieve array to remove (pre-sieve) the multiples of small primes. - -* Wheel (abstract class) - Wheel factorization is used to skip multiples of small primes e.g. - <= 7 to speed up the sieve of Eratosthenes. The abstract Wheel - class is used to initialize sieving primes i.e. addSievingPrime() - calculates the first multiple >= start of each sieving prime and - the position within the SieveOfEratosthenes array of that multiple - (multipleIndex). The unsetBit() method is used to cross-off a - multiple (unset a bit) and to calculate the sieving prime's next - multiple. - -* EratSmall (derived from Wheel) - Segmented sieve of Eratosthenes algorithm with a hard-coded - modulo 30 wheel that skips multiples of 2, 3 and 5. This algorithm - is optimized for small sieving primes that have many multiples in - each segment. EratSmall is a further optimized implementation of - Achim Flammenkamp's algorithm.[9] - -* EratMedium (derived from Wheel) - Segmented sieve of Eratosthenes algorithm with a fixed modulo 210 - wheel that skips multiples of 2, 3, 5 and 7. The wheel is - implemented using a precomputed lookup table (wheel210 array from - Wheel.cpp). This algorithm is optimized for medium sieving primes - with a few multiples per segment. - -* EratBig (derived from Wheel) - Segmented sieve of Eratosthenes algorithm with Tomás Oliveira's - improvement for big sieving primes [11] and a fixed modulo 210 - wheel that skips multiples of 2, 3, 5 and 7. The wheel is - implemented using a precomputed lookup table (wheel210 array from - Wheel.cpp). EratBig is optimized for big sieving primes that have - less than one multiple per segment. - -* iterator - primesieve::iterator allows to easily iterate over primes. It - provides next_prime() and prev_prime() methods. primesieve::iterator - works using a cache of primes of size sqrt(stop), once there are - no more primes available in the cache primesieve::iterator will - reload the cache with new primes. - -Other files ------------ -* include/primesieve.hpp - This header contains primesieve's new API first released in - primesieve-5.0. It is mostly a wrapper around the methods of the - PrimeSieve and ParallelPrimeSieve classes. - -* api.cpp - primesieve C++ API. - This file contains the implementations of the functions declared - in include/primesieve.hpp. - -* api-c.cpp - primesieve C API. - This file contains the implementations of the functions declared - in include/primesieve.h. - -* include/primesieve/config.hpp - Contains compile time constants that set the size of various - arrays and limits within primesieve. You can set these constants - according to your CPU type to get the best performance. - -References -========== - -[1] Richard C. Singleton, "An efficient prime number generator", - Communications of the ACM 12, 563-564, 1969. -[2] R. P. Brent, "The first occurrence of large gaps between - successive primes", Mathematics of Computation, 27:959-963, - 1973. -[3] C. Bays and R. Hudson, "The segmented sieve of Eratosthenes and - primes in arithmetic progressions to 10^12", BIT 17:121 127, - 1977. -[4] Paul Pritchard, "Fast compact prime number sieves (among - others)", Journal of Algorithms 4 (1983), 332-344. -[5] J. Sorenson, "An Introduction To Prime Number Sieves", Computer - Science Technical Report Vol. 909, January 1990. - http://research.cs.wisc.edu/techreports/1990/TR909.pdf -[6] J. Sorenson, "An analysis of two prime number sieves", Computer - Science Technical Report Vol. 1028, June 1991. - http://research.cs.wisc.edu/techreports/1991/TR1028.pdf -[7] J. Sorenson and I. Parberry, "Two Fast Parallel Prime Number - Sieves", Information and Computation, Vol. 114, No. 1, 1994. - http://larc.unt.edu/ian/pubs/sieve.pdf -[8] J. Sorenson, "Trading Time for Space in Prime Number Sieves", - Lecture Notes in Computer Science, Vol. 1423 (1998), 179-194. -[9] Achim Flammenkamp, "The Art of Prime Sieving", 1998. - http://wwwhomes.uni-bielefeld.de/achim/prime_sieve.html -[10] Jörg Richstein, "Segmentierung und Optimierung von Algorithmen - zu Problemen aus der Zahlentheorie", Gießen, Univ., Diss., 1999. -[11] Tomás Oliveira e Silva, "Fast implementation of the segmented - sieve of Eratosthenes", 2002. - http://www.ieeta.pt/~tos/software/prime_sieve.html -[12] A. Járai and E. Vatai, "Cache optimized linear sieve", Acta - Univ. Sapientiae, Informatica, 3, 2 (2011) 205-223. - http://www.acta.sapientia.ro/acta-info/C3-2/info32-5.pdf diff -Nru primesieve-6.3+ds/src/primesieve/SieveOfEratosthenes.cpp primesieve-7.0+ds/src/primesieve/SieveOfEratosthenes.cpp --- primesieve-6.3+ds/src/primesieve/SieveOfEratosthenes.cpp 2017-11-18 12:38:21.000000000 +0000 +++ primesieve-7.0+ds/src/primesieve/SieveOfEratosthenes.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,192 +0,0 @@ -/// -/// @file SieveOfEratosthenes.cpp -/// @brief The SieveOfEratosthenes class manages prime sieving -/// using the PreSieve, EratSmall, EratMedium and -/// EratBig classes. -/// -/// Copyright (C) 2017 Kim Walisch, -/// -/// This file is distributed under the BSD License. See the COPYING -/// file in the top level directory. -/// - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -using namespace std; -using namespace primesieve; - -namespace { - -/// unset bits < start -const byte_t unsetSmaller[32] = -{ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xfe, 0xfe, 0xfe, 0xfe, 0xfc, 0xfc, - 0xf8, 0xf8, 0xf8, 0xf8, 0xf0, 0xf0, 0xe0, - 0xe0, 0xe0, 0xe0, 0xc0, 0xc0, 0xc0, 0xc0, - 0xc0, 0xc0, 0x80, 0x80 -}; - -/// unset bits > stop -const byte_t unsetLarger[32] = -{ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x01, 0x01, 0x01, 0x01, 0x03, 0x03, 0x07, - 0x07, 0x07, 0x07, 0x0f, 0x0f, 0x1f, 0x1f, - 0x1f, 0x1f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, - 0x3f, 0x7f, 0x7f, 0xff -}; - -} // namespace - -namespace primesieve { - -/// De Bruijn bitscan table -const uint64_t SieveOfEratosthenes::bruijnBitValues_[64] = -{ - 7, 47, 11, 49, 67, 113, 13, 53, - 89, 71, 161, 101, 119, 187, 17, 233, - 59, 79, 91, 73, 133, 139, 163, 103, - 149, 121, 203, 169, 191, 217, 19, 239, - 43, 61, 109, 83, 157, 97, 181, 229, - 77, 131, 137, 143, 199, 167, 211, 41, - 107, 151, 179, 227, 127, 197, 209, 37, - 173, 223, 193, 31, 221, 29, 23, 241 -}; - -/// @start: Sieve primes >= start -/// @stop: Sieve primes <= stop -/// @sieveSize: Sieve size in kilobytes -/// @preSieve: Pre-sieve primes -/// -SieveOfEratosthenes::SieveOfEratosthenes(uint64_t start, - uint64_t stop, - uint64_t sieveSize, - const PreSieve& preSieve) : - start_(start), - stop_(stop), - sqrtStop_(isqrt(stop)), - preSieve_(preSieve), - maxPreSieve_(preSieve.getMaxPrime()), - sieve_(nullptr) -{ - if (start_ < 7) - throw primesieve_error("SieveOfEratosthenes: start must be >= 7"); - if (start_ > stop_) - throw primesieve_error("SieveOfEratosthenes: start must be <= stop"); - - sieveSize_ = floorPow2(sieveSize); - sieveSize_ = inBetween(8, sieveSize_, 4096); - sieveSize_ *= 1024; - - uint64_t rem = getByteRemainder(start_); - uint64_t dist = sieveSize_ * NUMBERS_PER_BYTE + 1; - segmentLow_ = start_ - rem; - segmentHigh_ = checkedAdd(segmentLow_, dist); - - allocate(); -} - -void SieveOfEratosthenes::allocate() -{ - deleteSieve_.reset(new byte_t[sieveSize_]); - sieve_ = deleteSieve_.get(); - - uint64_t l1Size = EratSmall::getL1Size(sieveSize_); - maxEratSmall_ = (uint64_t) (l1Size * config::FACTOR_ERATSMALL); - maxEratMedium_ = (uint64_t) (sieveSize_ * config::FACTOR_ERATMEDIUM); - - if (sqrtStop_ > maxPreSieve_) eratSmall_.reset(new EratSmall (stop_, l1Size, maxEratSmall_)); - if (sqrtStop_ > maxEratSmall_) eratMedium_.reset(new EratMedium(stop_, sieveSize_, maxEratMedium_)); - if (sqrtStop_ > maxEratMedium_) eratBig_.reset(new EratBig (stop_, sieveSize_, sqrtStop_)); -} - -uint64_t SieveOfEratosthenes::getSqrtStop() const -{ - return sqrtStop_; -} - -uint64_t SieveOfEratosthenes::getByteRemainder(uint64_t n) -{ - uint64_t r = n % NUMBERS_PER_BYTE; - if (r <= 1) - r += NUMBERS_PER_BYTE; - return r; -} - -/// Pre-sieve multiples of small primes e.g. <= 19 -/// to speed up the sieve of Eratosthenes -/// -void SieveOfEratosthenes::preSieve() -{ - preSieve_.copy(sieve_, sieveSize_, segmentLow_); - - // unset bits < start - if (segmentLow_ <= start_) - { - if (start_ <= maxPreSieve_) - sieve_[0] = 0xff; - uint64_t rem = getByteRemainder(start_); - sieve_[0] &= unsetSmaller[rem]; - } -} - -void SieveOfEratosthenes::crossOffMultiples() -{ - if (eratSmall_) eratSmall_->crossOff(sieve_, sieveSize_); - if (eratMedium_) eratMedium_->crossOff(sieve_, sieveSize_); - if (eratBig_) eratBig_->crossOff(sieve_); -} - -void SieveOfEratosthenes::sieveSegment() -{ - preSieve(); - crossOffMultiples(); - generatePrimes(sieve_, sieveSize_); - - // update for next segment - uint64_t dist = sieveSize_ * NUMBERS_PER_BYTE; - segmentLow_ = checkedAdd(segmentLow_, dist); - segmentHigh_ = checkedAdd(segmentHigh_, dist); -} - -/// Sieve the remaining segments, most segments -/// are sieved in addSievingPrime() -/// -void SieveOfEratosthenes::sieve() -{ - while (segmentHigh_ < stop_) - sieveSegment(); - - uint64_t rem = getByteRemainder(stop_); - uint64_t dist = (stop_ - rem) - segmentLow_; - sieveSize_ = dist / NUMBERS_PER_BYTE + 1; - dist = sieveSize_ * NUMBERS_PER_BYTE + 1; - segmentHigh_ = checkedAdd(segmentLow_, dist); - - // sieve last segment - preSieve(); - crossOffMultiples(); - - // unset bits > stop - sieve_[sieveSize_ - 1] &= unsetLarger[rem]; - - // unset bytes > stop - if (sieveSize_ % 8) - memset(&sieve_[sieveSize_], 0, 8 - sieveSize_ % 8); - - generatePrimes(sieve_, sieveSize_); -} - -} // namespace diff -Nru primesieve-6.3+ds/src/primesieve/SievingPrimes.cpp primesieve-7.0+ds/src/primesieve/SievingPrimes.cpp --- primesieve-6.3+ds/src/primesieve/SievingPrimes.cpp 2017-11-18 12:38:21.000000000 +0000 +++ primesieve-7.0+ds/src/primesieve/SievingPrimes.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,78 +0,0 @@ -/// -/// @file SievingPrimes.cpp -/// Generates the sieving primes up to sqrt(stop) -/// and adds them to PrimeGenerator. -/// -/// Copyright (C) 2017 Kim Walisch, -/// -/// This file is distributed under the BSD License. See the COPYING -/// file in the top level directory. -/// - -#include -#include -#include -#include -#include -#include - -#include -#include - -using namespace std; - -namespace primesieve { - -SievingPrimes::SievingPrimes(PrimeGenerator& primeGen, const PreSieve& preSieve) : - SieveOfEratosthenes(preSieve.getMaxPrime() + 1, - primeGen.getSqrtStop(), - primeGen.getSieveSize() / 1024, - preSieve), - primeGen_(primeGen) -{ } - -void SievingPrimes::generate() -{ - tinyPrimes(); - sieve(); -} - -/// Generate the primes up to sqrt(sqrt(stop)) -/// using the sieve of Eratosthenes -/// -void SievingPrimes::tinyPrimes() -{ - uint64_t n = getSqrtStop(); - vector isPrime(n + 1, true); - - for (uint64_t i = 3; i * i <= n; i += 2) - if (isPrime[i]) - for (uint64_t j = i * i; j <= n; j += i * 2) - isPrime[j] = false; - - uint64_t s = getStart(); - s += (~s & 1); - - for (uint64_t i = s; i <= n; i += 2) - if (isPrime[i]) - addSievingPrime(i); -} - -/// Reconstruct primes <= sqrt(stop) from 1 bits of the -/// sieve array and add them to PrimeGen -/// -void SievingPrimes::generatePrimes(const byte_t* sieve, uint64_t sieveSize) -{ - uint64_t low = getSegmentLow(); - - for (uint64_t i = 0; i < sieveSize; i += 8) - { - uint64_t bits = littleendian_cast(&sieve[i]); - while (bits) - primeGen_.addSievingPrime(nextPrime(&bits, low)); - - low += NUMBERS_PER_BYTE * 8; - } -} - -} // namespace diff -Nru primesieve-6.3+ds/src/primesieve/Wheel.cpp primesieve-7.0+ds/src/primesieve/Wheel.cpp --- primesieve-6.3+ds/src/primesieve/Wheel.cpp 2017-11-18 12:38:21.000000000 +0000 +++ primesieve-7.0+ds/src/primesieve/Wheel.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,175 +0,0 @@ -/// -/// @file Wheel.cpp -/// @brief Precomputed arrays for wheel factorization. -/// -/// Copyright (C) 2017 Kim Walisch, -/// -/// This file is distributed under the BSD License. See the COPYING -/// file in the top level directory. -/// - -#include -#include - -namespace primesieve { - -const WheelInit wheel30Init[30] = -{ - {1, 0}, {0, 0}, {5, 1}, {4, 1}, {3, 1}, {2, 1}, {1, 1}, {0, 1}, - {3, 2}, {2, 2}, {1, 2}, {0, 2}, {1, 3}, {0, 3}, {3, 4}, {2, 4}, - {1, 4}, {0, 4}, {1, 5}, {0, 5}, {3, 6}, {2, 6}, {1, 6}, {0, 6}, - {5, 7}, {4, 7}, {3, 7}, {2, 7}, {1, 7}, {0, 7} -}; - -const WheelInit wheel210Init[210] = -{ - {1, 0}, {0, 0}, {9, 1}, {8, 1}, {7, 1}, {6, 1}, {5, 1}, {4, 1}, - {3, 1}, {2, 1}, {1, 1}, {0, 1}, {1, 2}, {0, 2}, {3, 3}, {2, 3}, - {1, 3}, {0, 3}, {1, 4}, {0, 4}, {3, 5}, {2, 5}, {1, 5}, {0, 5}, - {5, 6}, {4, 6}, {3, 6}, {2, 6}, {1, 6}, {0, 6}, {1, 7}, {0, 7}, - {5, 8}, {4, 8}, {3, 8}, {2, 8}, {1, 8}, {0, 8}, {3, 9}, {2, 9}, - {1, 9}, {0, 9}, {1, 10}, {0, 10}, {3, 11}, {2, 11}, {1, 11}, {0, 11}, - {5, 12}, {4, 12}, {3, 12}, {2, 12}, {1, 12}, {0, 12}, {5, 13}, {4, 13}, - {3, 13}, {2, 13}, {1, 13}, {0, 13}, {1, 14}, {0, 14}, {5, 15}, {4, 15}, - {3, 15}, {2, 15}, {1, 15}, {0, 15}, {3, 16}, {2, 16}, {1, 16}, {0, 16}, - {1, 17}, {0, 17}, {5, 18}, {4, 18}, {3, 18}, {2, 18}, {1, 18}, {0, 18}, - {3, 19}, {2, 19}, {1, 19}, {0, 19}, {5, 20}, {4, 20}, {3, 20}, {2, 20}, - {1, 20}, {0, 20}, {7, 21}, {6, 21}, {5, 21}, {4, 21}, {3, 21}, {2, 21}, - {1, 21}, {0, 21}, {3, 22}, {2, 22}, {1, 22}, {0, 22}, {1, 23}, {0, 23}, - {3, 24}, {2, 24}, {1, 24}, {0, 24}, {1, 25}, {0, 25}, {3, 26}, {2, 26}, - {1, 26}, {0, 26}, {7, 27}, {6, 27}, {5, 27}, {4, 27}, {3, 27}, {2, 27}, - {1, 27}, {0, 27}, {5, 28}, {4, 28}, {3, 28}, {2, 28}, {1, 28}, {0, 28}, - {3, 29}, {2, 29}, {1, 29}, {0, 29}, {5, 30}, {4, 30}, {3, 30}, {2, 30}, - {1, 30}, {0, 30}, {1, 31}, {0, 31}, {3, 32}, {2, 32}, {1, 32}, {0, 32}, - {5, 33}, {4, 33}, {3, 33}, {2, 33}, {1, 33}, {0, 33}, {1, 34}, {0, 34}, - {5, 35}, {4, 35}, {3, 35}, {2, 35}, {1, 35}, {0, 35}, {5, 36}, {4, 36}, - {3, 36}, {2, 36}, {1, 36}, {0, 36}, {3, 37}, {2, 37}, {1, 37}, {0, 37}, - {1, 38}, {0, 38}, {3, 39}, {2, 39}, {1, 39}, {0, 39}, {5, 40}, {4, 40}, - {3, 40}, {2, 40}, {1, 40}, {0, 40}, {1, 41}, {0, 41}, {5, 42}, {4, 42}, - {3, 42}, {2, 42}, {1, 42}, {0, 42}, {3, 43}, {2, 43}, {1, 43}, {0, 43}, - {1, 44}, {0, 44}, {3, 45}, {2, 45}, {1, 45}, {0, 45}, {1, 46}, {0, 46}, - {9, 47}, {8, 47}, {7, 47}, {6, 47}, {5, 47}, {4, 47}, {3, 47}, {2, 47}, - {1, 47}, {0, 47} -}; - -const WheelElement wheel30[8*8] = -{ - { BIT0, 6, 1, 1 }, { BIT4, 4, 1, 1 }, { BIT3, 2, 0, 1 }, { BIT7, 4, 1, 1 }, - { BIT6, 2, 1, 1 }, { BIT2, 4, 1, 1 }, { BIT1, 6, 1, 1 }, { BIT5, 2, 1, -7 }, - { BIT1, 6, 2, 1 }, { BIT3, 4, 1, 1 }, { BIT7, 2, 1, 1 }, { BIT5, 4, 2, 1 }, - { BIT0, 2, 0, 1 }, { BIT6, 4, 2, 1 }, { BIT2, 6, 2, 1 }, { BIT4, 2, 1, -7 }, - { BIT2, 6, 2, 1 }, { BIT7, 4, 2, 1 }, { BIT5, 2, 1, 1 }, { BIT4, 4, 2, 1 }, - { BIT1, 2, 1, 1 }, { BIT0, 4, 1, 1 }, { BIT6, 6, 3, 1 }, { BIT3, 2, 1, -7 }, - { BIT3, 6, 3, 1 }, { BIT6, 4, 3, 1 }, { BIT0, 2, 1, 1 }, { BIT1, 4, 2, 1 }, - { BIT4, 2, 1, 1 }, { BIT5, 4, 2, 1 }, { BIT7, 6, 4, 1 }, { BIT2, 2, 1, -7 }, - { BIT4, 6, 4, 1 }, { BIT2, 4, 2, 1 }, { BIT6, 2, 2, 1 }, { BIT0, 4, 2, 1 }, - { BIT5, 2, 1, 1 }, { BIT7, 4, 3, 1 }, { BIT3, 6, 4, 1 }, { BIT1, 2, 1, -7 }, - { BIT5, 6, 5, 1 }, { BIT1, 4, 3, 1 }, { BIT2, 2, 1, 1 }, { BIT6, 4, 3, 1 }, - { BIT7, 2, 2, 1 }, { BIT3, 4, 3, 1 }, { BIT4, 6, 5, 1 }, { BIT0, 2, 1, -7 }, - { BIT6, 6, 6, 1 }, { BIT5, 4, 4, 1 }, { BIT4, 2, 2, 1 }, { BIT3, 4, 4, 1 }, - { BIT2, 2, 2, 1 }, { BIT1, 4, 4, 1 }, { BIT0, 6, 5, 1 }, { BIT7, 2, 2, -7 }, - { BIT7, 6, 1, 1 }, { BIT0, 4, 0, 1 }, { BIT1, 2, 0, 1 }, { BIT2, 4, 0, 1 }, - { BIT3, 2, 0, 1 }, { BIT4, 4, 0, 1 }, { BIT5, 6, 0, 1 }, { BIT6, 2, 0, -7 } -}; - -const WheelElement wheel210[48*8] = -{ - { BIT0, 10, 2, 1 }, { BIT3, 2, 0, 1 }, { BIT7, 4, 1, 1 }, { BIT6, 2, 1, 1 }, - { BIT2, 4, 1, 1 }, { BIT1, 6, 1, 1 }, { BIT5, 2, 1, 1 }, { BIT0, 6, 1, 1 }, - { BIT4, 4, 1, 1 }, { BIT3, 2, 0, 1 }, { BIT7, 4, 1, 1 }, { BIT6, 6, 2, 1 }, - { BIT1, 6, 1, 1 }, { BIT5, 2, 1, 1 }, { BIT0, 6, 1, 1 }, { BIT4, 4, 1, 1 }, - { BIT3, 2, 0, 1 }, { BIT7, 6, 2, 1 }, { BIT2, 4, 1, 1 }, { BIT1, 6, 1, 1 }, - { BIT5, 8, 2, 1 }, { BIT4, 4, 1, 1 }, { BIT3, 2, 0, 1 }, { BIT7, 4, 1, 1 }, - { BIT6, 2, 1, 1 }, { BIT2, 4, 1, 1 }, { BIT1, 8, 2, 1 }, { BIT0, 6, 1, 1 }, - { BIT4, 4, 1, 1 }, { BIT3, 6, 1, 1 }, { BIT6, 2, 1, 1 }, { BIT2, 4, 1, 1 }, - { BIT1, 6, 1, 1 }, { BIT5, 2, 1, 1 }, { BIT0, 6, 1, 1 }, { BIT4, 6, 1, 1 }, - { BIT7, 4, 1, 1 }, { BIT6, 2, 1, 1 }, { BIT2, 4, 1, 1 }, { BIT1, 6, 1, 1 }, - { BIT5, 2, 1, 1 }, { BIT0, 6, 1, 1 }, { BIT4, 4, 1, 1 }, { BIT3, 2, 0, 1 }, - { BIT7, 4, 1, 1 }, { BIT6, 2, 1, 1 }, { BIT2, 10, 2, 1 }, { BIT5, 2, 1, -47 }, - { BIT1, 10, 3, 1 }, { BIT7, 2, 1, 1 }, { BIT5, 4, 2, 1 }, { BIT0, 2, 0, 1 }, - { BIT6, 4, 2, 1 }, { BIT2, 6, 2, 1 }, { BIT4, 2, 1, 1 }, { BIT1, 6, 2, 1 }, - { BIT3, 4, 1, 1 }, { BIT7, 2, 1, 1 }, { BIT5, 4, 2, 1 }, { BIT0, 6, 2, 1 }, - { BIT2, 6, 2, 1 }, { BIT4, 2, 1, 1 }, { BIT1, 6, 2, 1 }, { BIT3, 4, 1, 1 }, - { BIT7, 2, 1, 1 }, { BIT5, 6, 2, 1 }, { BIT6, 4, 2, 1 }, { BIT2, 6, 2, 1 }, - { BIT4, 8, 3, 1 }, { BIT3, 4, 1, 1 }, { BIT7, 2, 1, 1 }, { BIT5, 4, 2, 1 }, - { BIT0, 2, 0, 1 }, { BIT6, 4, 2, 1 }, { BIT2, 8, 3, 1 }, { BIT1, 6, 2, 1 }, - { BIT3, 4, 1, 1 }, { BIT7, 6, 3, 1 }, { BIT0, 2, 0, 1 }, { BIT6, 4, 2, 1 }, - { BIT2, 6, 2, 1 }, { BIT4, 2, 1, 1 }, { BIT1, 6, 2, 1 }, { BIT3, 6, 2, 1 }, - { BIT5, 4, 2, 1 }, { BIT0, 2, 0, 1 }, { BIT6, 4, 2, 1 }, { BIT2, 6, 2, 1 }, - { BIT4, 2, 1, 1 }, { BIT1, 6, 2, 1 }, { BIT3, 4, 1, 1 }, { BIT7, 2, 1, 1 }, - { BIT5, 4, 2, 1 }, { BIT0, 2, 0, 1 }, { BIT6, 10, 4, 1 }, { BIT4, 2, 1, -47 }, - { BIT2, 10, 4, 1 }, { BIT5, 2, 1, 1 }, { BIT4, 4, 2, 1 }, { BIT1, 2, 1, 1 }, - { BIT0, 4, 1, 1 }, { BIT6, 6, 3, 1 }, { BIT3, 2, 1, 1 }, { BIT2, 6, 2, 1 }, - { BIT7, 4, 2, 1 }, { BIT5, 2, 1, 1 }, { BIT4, 4, 2, 1 }, { BIT1, 6, 2, 1 }, - { BIT6, 6, 3, 1 }, { BIT3, 2, 1, 1 }, { BIT2, 6, 2, 1 }, { BIT7, 4, 2, 1 }, - { BIT5, 2, 1, 1 }, { BIT4, 6, 3, 1 }, { BIT0, 4, 1, 1 }, { BIT6, 6, 3, 1 }, - { BIT3, 8, 3, 1 }, { BIT7, 4, 2, 1 }, { BIT5, 2, 1, 1 }, { BIT4, 4, 2, 1 }, - { BIT1, 2, 1, 1 }, { BIT0, 4, 1, 1 }, { BIT6, 8, 4, 1 }, { BIT2, 6, 2, 1 }, - { BIT7, 4, 2, 1 }, { BIT5, 6, 3, 1 }, { BIT1, 2, 1, 1 }, { BIT0, 4, 1, 1 }, - { BIT6, 6, 3, 1 }, { BIT3, 2, 1, 1 }, { BIT2, 6, 2, 1 }, { BIT7, 6, 3, 1 }, - { BIT4, 4, 2, 1 }, { BIT1, 2, 1, 1 }, { BIT0, 4, 1, 1 }, { BIT6, 6, 3, 1 }, - { BIT3, 2, 1, 1 }, { BIT2, 6, 2, 1 }, { BIT7, 4, 2, 1 }, { BIT5, 2, 1, 1 }, - { BIT4, 4, 2, 1 }, { BIT1, 2, 1, 1 }, { BIT0, 10, 4, 1 }, { BIT3, 2, 1, -47 }, - { BIT3, 10, 6, 1 }, { BIT0, 2, 1, 1 }, { BIT1, 4, 2, 1 }, { BIT4, 2, 1, 1 }, - { BIT5, 4, 2, 1 }, { BIT7, 6, 4, 1 }, { BIT2, 2, 1, 1 }, { BIT3, 6, 3, 1 }, - { BIT6, 4, 3, 1 }, { BIT0, 2, 1, 1 }, { BIT1, 4, 2, 1 }, { BIT4, 6, 3, 1 }, - { BIT7, 6, 4, 1 }, { BIT2, 2, 1, 1 }, { BIT3, 6, 3, 1 }, { BIT6, 4, 3, 1 }, - { BIT0, 2, 1, 1 }, { BIT1, 6, 3, 1 }, { BIT5, 4, 2, 1 }, { BIT7, 6, 4, 1 }, - { BIT2, 8, 4, 1 }, { BIT6, 4, 3, 1 }, { BIT0, 2, 1, 1 }, { BIT1, 4, 2, 1 }, - { BIT4, 2, 1, 1 }, { BIT5, 4, 2, 1 }, { BIT7, 8, 5, 1 }, { BIT3, 6, 3, 1 }, - { BIT6, 4, 3, 1 }, { BIT0, 6, 3, 1 }, { BIT4, 2, 1, 1 }, { BIT5, 4, 2, 1 }, - { BIT7, 6, 4, 1 }, { BIT2, 2, 1, 1 }, { BIT3, 6, 3, 1 }, { BIT6, 6, 4, 1 }, - { BIT1, 4, 2, 1 }, { BIT4, 2, 1, 1 }, { BIT5, 4, 2, 1 }, { BIT7, 6, 4, 1 }, - { BIT2, 2, 1, 1 }, { BIT3, 6, 3, 1 }, { BIT6, 4, 3, 1 }, { BIT0, 2, 1, 1 }, - { BIT1, 4, 2, 1 }, { BIT4, 2, 1, 1 }, { BIT5, 10, 6, 1 }, { BIT2, 2, 1, -47 }, - { BIT4, 10, 6, 1 }, { BIT6, 2, 2, 1 }, { BIT0, 4, 2, 1 }, { BIT5, 2, 1, 1 }, - { BIT7, 4, 3, 1 }, { BIT3, 6, 4, 1 }, { BIT1, 2, 1, 1 }, { BIT4, 6, 4, 1 }, - { BIT2, 4, 2, 1 }, { BIT6, 2, 2, 1 }, { BIT0, 4, 2, 1 }, { BIT5, 6, 4, 1 }, - { BIT3, 6, 4, 1 }, { BIT1, 2, 1, 1 }, { BIT4, 6, 4, 1 }, { BIT2, 4, 2, 1 }, - { BIT6, 2, 2, 1 }, { BIT0, 6, 3, 1 }, { BIT7, 4, 3, 1 }, { BIT3, 6, 4, 1 }, - { BIT1, 8, 5, 1 }, { BIT2, 4, 2, 1 }, { BIT6, 2, 2, 1 }, { BIT0, 4, 2, 1 }, - { BIT5, 2, 1, 1 }, { BIT7, 4, 3, 1 }, { BIT3, 8, 5, 1 }, { BIT4, 6, 4, 1 }, - { BIT2, 4, 2, 1 }, { BIT6, 6, 4, 1 }, { BIT5, 2, 1, 1 }, { BIT7, 4, 3, 1 }, - { BIT3, 6, 4, 1 }, { BIT1, 2, 1, 1 }, { BIT4, 6, 4, 1 }, { BIT2, 6, 4, 1 }, - { BIT0, 4, 2, 1 }, { BIT5, 2, 1, 1 }, { BIT7, 4, 3, 1 }, { BIT3, 6, 4, 1 }, - { BIT1, 2, 1, 1 }, { BIT4, 6, 4, 1 }, { BIT2, 4, 2, 1 }, { BIT6, 2, 2, 1 }, - { BIT0, 4, 2, 1 }, { BIT5, 2, 1, 1 }, { BIT7, 10, 7, 1 }, { BIT1, 2, 1, -47 }, - { BIT5, 10, 8, 1 }, { BIT2, 2, 1, 1 }, { BIT6, 4, 3, 1 }, { BIT7, 2, 2, 1 }, - { BIT3, 4, 3, 1 }, { BIT4, 6, 5, 1 }, { BIT0, 2, 1, 1 }, { BIT5, 6, 5, 1 }, - { BIT1, 4, 3, 1 }, { BIT2, 2, 1, 1 }, { BIT6, 4, 3, 1 }, { BIT7, 6, 5, 1 }, - { BIT4, 6, 5, 1 }, { BIT0, 2, 1, 1 }, { BIT5, 6, 5, 1 }, { BIT1, 4, 3, 1 }, - { BIT2, 2, 1, 1 }, { BIT6, 6, 5, 1 }, { BIT3, 4, 3, 1 }, { BIT4, 6, 5, 1 }, - { BIT0, 8, 6, 1 }, { BIT1, 4, 3, 1 }, { BIT2, 2, 1, 1 }, { BIT6, 4, 3, 1 }, - { BIT7, 2, 2, 1 }, { BIT3, 4, 3, 1 }, { BIT4, 8, 6, 1 }, { BIT5, 6, 5, 1 }, - { BIT1, 4, 3, 1 }, { BIT2, 6, 4, 1 }, { BIT7, 2, 2, 1 }, { BIT3, 4, 3, 1 }, - { BIT4, 6, 5, 1 }, { BIT0, 2, 1, 1 }, { BIT5, 6, 5, 1 }, { BIT1, 6, 4, 1 }, - { BIT6, 4, 3, 1 }, { BIT7, 2, 2, 1 }, { BIT3, 4, 3, 1 }, { BIT4, 6, 5, 1 }, - { BIT0, 2, 1, 1 }, { BIT5, 6, 5, 1 }, { BIT1, 4, 3, 1 }, { BIT2, 2, 1, 1 }, - { BIT6, 4, 3, 1 }, { BIT7, 2, 2, 1 }, { BIT3, 10, 8, 1 }, { BIT0, 2, 1, -47 }, - { BIT6, 10,10, 1 }, { BIT4, 2, 2, 1 }, { BIT3, 4, 4, 1 }, { BIT2, 2, 2, 1 }, - { BIT1, 4, 4, 1 }, { BIT0, 6, 5, 1 }, { BIT7, 2, 2, 1 }, { BIT6, 6, 6, 1 }, - { BIT5, 4, 4, 1 }, { BIT4, 2, 2, 1 }, { BIT3, 4, 4, 1 }, { BIT2, 6, 6, 1 }, - { BIT0, 6, 5, 1 }, { BIT7, 2, 2, 1 }, { BIT6, 6, 6, 1 }, { BIT5, 4, 4, 1 }, - { BIT4, 2, 2, 1 }, { BIT3, 6, 6, 1 }, { BIT1, 4, 4, 1 }, { BIT0, 6, 5, 1 }, - { BIT7, 8, 8, 1 }, { BIT5, 4, 4, 1 }, { BIT4, 2, 2, 1 }, { BIT3, 4, 4, 1 }, - { BIT2, 2, 2, 1 }, { BIT1, 4, 4, 1 }, { BIT0, 8, 7, 1 }, { BIT6, 6, 6, 1 }, - { BIT5, 4, 4, 1 }, { BIT4, 6, 6, 1 }, { BIT2, 2, 2, 1 }, { BIT1, 4, 4, 1 }, - { BIT0, 6, 5, 1 }, { BIT7, 2, 2, 1 }, { BIT6, 6, 6, 1 }, { BIT5, 6, 6, 1 }, - { BIT3, 4, 4, 1 }, { BIT2, 2, 2, 1 }, { BIT1, 4, 4, 1 }, { BIT0, 6, 5, 1 }, - { BIT7, 2, 2, 1 }, { BIT6, 6, 6, 1 }, { BIT5, 4, 4, 1 }, { BIT4, 2, 2, 1 }, - { BIT3, 4, 4, 1 }, { BIT2, 2, 2, 1 }, { BIT1, 10, 9, 1 }, { BIT7, 2, 2, -47 }, - { BIT7, 10, 1, 1 }, { BIT1, 2, 0, 1 }, { BIT2, 4, 0, 1 }, { BIT3, 2, 0, 1 }, - { BIT4, 4, 0, 1 }, { BIT5, 6, 0, 1 }, { BIT6, 2, 0, 1 }, { BIT7, 6, 1, 1 }, - { BIT0, 4, 0, 1 }, { BIT1, 2, 0, 1 }, { BIT2, 4, 0, 1 }, { BIT3, 6, 0, 1 }, - { BIT5, 6, 0, 1 }, { BIT6, 2, 0, 1 }, { BIT7, 6, 1, 1 }, { BIT0, 4, 0, 1 }, - { BIT1, 2, 0, 1 }, { BIT2, 6, 0, 1 }, { BIT4, 4, 0, 1 }, { BIT5, 6, 0, 1 }, - { BIT6, 8, 1, 1 }, { BIT0, 4, 0, 1 }, { BIT1, 2, 0, 1 }, { BIT2, 4, 0, 1 }, - { BIT3, 2, 0, 1 }, { BIT4, 4, 0, 1 }, { BIT5, 8, 0, 1 }, { BIT7, 6, 1, 1 }, - { BIT0, 4, 0, 1 }, { BIT1, 6, 0, 1 }, { BIT3, 2, 0, 1 }, { BIT4, 4, 0, 1 }, - { BIT5, 6, 0, 1 }, { BIT6, 2, 0, 1 }, { BIT7, 6, 1, 1 }, { BIT0, 6, 0, 1 }, - { BIT2, 4, 0, 1 }, { BIT3, 2, 0, 1 }, { BIT4, 4, 0, 1 }, { BIT5, 6, 0, 1 }, - { BIT6, 2, 0, 1 }, { BIT7, 6, 1, 1 }, { BIT0, 4, 0, 1 }, { BIT1, 2, 0, 1 }, - { BIT2, 4, 0, 1 }, { BIT3, 2, 0, 1 }, { BIT4, 10, 0, 1 }, { BIT6, 2, 0, -47 } -}; - -} // namespace diff -Nru primesieve-6.3+ds/src/PrimeSieve.cpp primesieve-7.0+ds/src/PrimeSieve.cpp --- primesieve-6.3+ds/src/PrimeSieve.cpp 1970-01-01 00:00:00.000000000 +0000 +++ primesieve-7.0+ds/src/PrimeSieve.cpp 2018-06-08 08:51:41.000000000 +0000 @@ -0,0 +1,287 @@ +/// +/// @file PrimeSieve.cpp +/// @brief PrimeSieve is a high level class that manages prime +/// sieving. It is used for printing and counting primes +/// and for computing the nth prime. +/// +/// Copyright (C) 2018 Kim Walisch, +/// +/// This file is distributed under the BSD License. See the COPYING +/// file in the top level directory. +/// + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +using namespace std; + +namespace { + +struct SmallPrime +{ + uint64_t first; + uint64_t last; + int index; + string str; +}; + +const array smallPrimes +{{ + { 2, 2, 0, "2" }, + { 3, 3, 0, "3" }, + { 5, 5, 0, "5" }, + { 3, 5, 1, "(3, 5)" }, + { 5, 7, 1, "(5, 7)" }, + { 5, 11, 2, "(5, 7, 11)" }, + { 5, 13, 3, "(5, 7, 11, 13)" }, + { 5, 17, 4, "(5, 7, 11, 13, 17)" } +}}; + +} // namespace + +namespace primesieve { + +PrimeSieve::PrimeSieve() : + start_(0), + stop_(0), + flags_(COUNT_PRIMES), + parent_(nullptr) +{ + setSieveSize(get_sieve_size()); + reset(); +} + +/// ParallelSieve creates one PrimeSieve +/// child object for each thread. +/// +PrimeSieve::PrimeSieve(PrimeSieve* parent) : + sieveSize_(parent->sieveSize_), + flags_(parent->flags_), + parent_(parent) +{ } + +PrimeSieve::~PrimeSieve() +{ } + +void PrimeSieve::reset() +{ + counts_.fill(0); + seconds_ = 0.0; + toUpdate_ = 0; + processed_ = 0; + percent_ = -1.0; +} + +bool PrimeSieve::isParallelSieve() const +{ + return parent_ != nullptr; +} + +bool PrimeSieve::isFlag(int flag) const +{ + return (flags_ & flag) == flag; +} + +bool PrimeSieve::isFlag(int first, int last) const +{ + int mask = (last * 2) - first; + return (flags_ & mask) != 0; +} + +bool PrimeSieve::isCountPrimes() const { return isFlag(COUNT_PRIMES); } +bool PrimeSieve::isPrintPrimes() const { return isFlag(PRINT_PRIMES); } +bool PrimeSieve::isPrint() const { return isFlag(PRINT_PRIMES, PRINT_SEXTUPLETS); } +bool PrimeSieve::isCountkTuplets() const { return isFlag(COUNT_TWINS, COUNT_SEXTUPLETS); } +bool PrimeSieve::isPrintkTuplets() const { return isFlag(PRINT_TWINS, PRINT_SEXTUPLETS); } +bool PrimeSieve::isStatus() const { return isFlag(PRINT_STATUS, CALCULATE_STATUS); } +bool PrimeSieve::isCount(int i) const { return isFlag(COUNT_PRIMES << i); } +bool PrimeSieve::isPrint(int i) const { return isFlag(PRINT_PRIMES << i); } + +uint64_t PrimeSieve::getStart() const +{ + return start_; +} + +uint64_t PrimeSieve::getStop() const +{ + return stop_; +} + +uint64_t PrimeSieve::getDistance() const +{ + return stop_ - start_; +} + +uint64_t PrimeSieve::getCount(int i) const +{ + return counts_.at(i); +} + +counts_t& PrimeSieve::getCounts() +{ + return counts_; +} + +int PrimeSieve::getSieveSize() const +{ + return sieveSize_; +} + +double PrimeSieve::getSeconds() const +{ + return seconds_; +} + +double PrimeSieve::getStatus() const +{ + return percent_; +} + +void PrimeSieve::setFlags(int flags) +{ + flags_ = flags; +} + +void PrimeSieve::addFlags(int flags) +{ + flags_ |= flags; +} + +/// Set the size of the sieve array in kilobytes. +/// The best sieving performance is usually achieved if the +/// sieve size is set to the CPU's L1 or L2 cache size. +/// +void PrimeSieve::setSieveSize(int sieveSize) +{ + sieveSize_ = inBetween(8, sieveSize, 4096); + sieveSize_ = floorPow2(sieveSize_); +} + +/// Set a start number (lower bound) for sieving +void PrimeSieve::setStart(uint64_t start) +{ + start_ = start; +} + +/// Set a stop number (upper bound) for sieving +void PrimeSieve::setStop(uint64_t stop) +{ + stop_ = stop; +} + +/// Print status in percent to stdout. +/// @processed: Sum of recently processed segments +/// +bool PrimeSieve::updateStatus(uint64_t processed, bool tryLock) +{ + if (isParallelSieve()) + { + toUpdate_ += processed; + if (parent_->updateStatus(toUpdate_, tryLock)) + toUpdate_ = 0; + } + else + { + processed_ += processed; + double percent = 100; + if (getDistance() > 0) + percent = processed_ * 100.0 / getDistance(); + double old = percent_; + percent_ = min(percent, 100.0); + if (isFlag(PRINT_STATUS)) + printStatus(old, percent_); + } + return true; +} + +void PrimeSieve::printStatus(double old, double current) +{ + int percent = (int) current; + if (percent > (int) old) + { + cout << '\r' << percent << '%' << flush; + if (percent == 100) + cout << endl; + } +} + +/// Process small primes <= 5 and small k-tuplets <= 17 +void PrimeSieve::processSmallPrimes() +{ + for (auto& p : smallPrimes) + { + if (p.first >= start_ && p.last <= stop_) + { + if (isCount(p.index)) + counts_[p.index]++; + if (isPrint(p.index)) + cout << p.str << '\n'; + } + } +} + +uint64_t PrimeSieve::countPrimes(uint64_t start, uint64_t stop) +{ + sieve(start, stop, COUNT_PRIMES); + return getCount(0); +} + +void PrimeSieve::sieve(uint64_t start, uint64_t stop) +{ + setStart(start); + setStop(stop); + sieve(); +} + +void PrimeSieve::sieve(uint64_t start, uint64_t stop, int flags) +{ + setStart(start); + setStop(stop); + setFlags(flags); + sieve(); +} + +/// Sieve the primes and prime k-tuplets (twin primes, +/// prime triplets, ...) in [start, stop] +/// +void PrimeSieve::sieve() +{ + reset(); + + if (start_ > stop_) + return; + + auto t1 = chrono::system_clock::now(); + int initStatus = 0; + int finishStatus = 10; + + if (isStatus()) + updateStatus(initStatus); + + if (start_ <= 5) + processSmallPrimes(); + + if (stop_ >= 7) + { + PrintPrimes printPrimes(*this); + printPrimes.sieve(); + } + + auto t2 = chrono::system_clock::now(); + chrono::duration seconds = t2 - t1; + seconds_ = seconds.count(); + + if (isStatus()) + updateStatus(finishStatus, false); +} + +} // namespace diff -Nru primesieve-6.3+ds/src/PrintPrimes.cpp primesieve-7.0+ds/src/PrintPrimes.cpp --- primesieve-6.3+ds/src/PrintPrimes.cpp 1970-01-01 00:00:00.000000000 +0000 +++ primesieve-7.0+ds/src/PrintPrimes.cpp 2018-06-08 08:51:41.000000000 +0000 @@ -0,0 +1,198 @@ +/// +/// @file PrintPrimes.cpp +/// @brief PrintPrimes is used for printing primes to stdout and +/// for counting primes. After a segment has been sieved +/// (using Erat) PrintPrimes is used to reconstruct primes +/// and prime k-tuplets from 1 bits of the sieve array. +/// +/// Copyright (C) 2018 Kim Walisch, +/// +/// This file is distributed under the BSD License. See the COPYING +/// file in the top level directory. +/// + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +using namespace std; + +namespace primesieve { + +const uint64_t PrintPrimes::bitmasks_[6][5] = +{ + { END }, + { 0x06, 0x18, 0xc0, END }, // Twin primes: b00000110, b00011000, b11000000 + { 0x07, 0x0e, 0x1c, 0x38, END }, // Prime triplets: b00000111, b00001110, ... + { 0x1e, END }, // Prime quadruplets: b00011110 + { 0x1f, 0x3e, END }, // Prime quintuplets + { 0x3f, END } // Prime sextuplets +}; + +PrintPrimes::PrintPrimes(PrimeSieve& ps) : + preSieve_(ps.getStart(), ps.getStop()), + counts_(ps.getCounts()), + ps_(ps) +{ + uint64_t start = max(7, ps.getStart()); + uint64_t stop = ps.getStop(); + uint64_t sieveSize = ps.getSieveSize(); + + Erat::init(start, stop, sieveSize, preSieve_); + + if (ps_.isCountkTuplets()) + initCounts(); +} + +/// Initialize the lookup tables to count the number +/// of twins, triplets, ... per byte +/// +void PrintPrimes::initCounts() +{ + for (uint_t i = 1; i < counts_.size(); i++) + { + if (!ps_.isCount(i)) + continue; + + kCounts_[i].resize(256); + + for (uint64_t j = 0; j < 256; j++) + { + byte_t count = 0; + for (const uint64_t* b = bitmasks_[i]; *b <= j; b++) + { + if ((j & *b) == *b) + count++; + } + kCounts_[i][j] = count; + } + } +} + +void PrintPrimes::sieve() +{ + SievingPrimes sievingPrimes(this, preSieve_); + uint64_t prime = sievingPrimes.next(); + + while (hasNextSegment()) + { + low_ = segmentLow_; + uint64_t sqrtHigh = isqrt(segmentHigh_); + + for (; prime <= sqrtHigh; prime = sievingPrimes.next()) + addSievingPrime(prime); + + sieveSegment(); + print(); + } +} + +/// Executed after each sieved segment +void PrintPrimes::print() +{ + if (ps_.isCountPrimes()) + countPrimes(); + if (ps_.isCountkTuplets()) + countkTuplets(); + if (ps_.isPrintPrimes()) + printPrimes(); + if (ps_.isPrintkTuplets()) + printkTuplets(); + + if (ps_.isStatus()) + ps_.updateStatus(sieveSize_ * 30); +} + +void PrintPrimes::countPrimes() +{ + uint64_t size = ceilDiv(sieveSize_, 8); + counts_[0] += popcount((const uint64_t*) sieve_, size); +} + +void PrintPrimes::countkTuplets() +{ + // i = 1 twins, i = 2 triplets, ... + for (uint_t i = 1; i < counts_.size(); i++) + { + if (!ps_.isCount(i)) + continue; + + uint64_t sum = 0; + + for (uint64_t j = 0; j < sieveSize_; j += 4) + { + sum += kCounts_[i][sieve_[j+0]]; + sum += kCounts_[i][sieve_[j+1]]; + sum += kCounts_[i][sieve_[j+2]]; + sum += kCounts_[i][sieve_[j+3]]; + } + + counts_[i] += sum; + } +} + +/// Print primes to stdout +void PrintPrimes::printPrimes() const +{ + uint64_t i = 0; + uint64_t low = low_; + + while (i < sieveSize_) + { + uint64_t size = min(i + (1 << 16), sieveSize_); + ostringstream primes; + + for (; i < size; i += 8) + { + uint64_t bits = littleendian_cast(&sieve_[i]); + while (bits) + primes << nextPrime(&bits, low) << '\n'; + + low += 8 * 30; + } + + cout << primes.str(); + } +} + +/// Print prime k-tuplets to stdout +void PrintPrimes::printkTuplets() const +{ + ostringstream kTuplets; + // i = 1 twins, i = 2 triplets, ... + uint_t i = 1; + uint64_t low = low_; + + for (; !ps_.isPrint(i); i++); + + for (uint64_t j = 0; j < sieveSize_; j++, low += 30) + { + for (const uint64_t* bitmask = bitmasks_[i]; *bitmask <= sieve_[j]; bitmask++) + { + if ((sieve_[j] & *bitmask) == *bitmask) + { + kTuplets << "("; + uint64_t bits = *bitmask; + while (bits != 0) + { + kTuplets << nextPrime(&bits, low); + kTuplets << ((bits != 0) ? ", " : ")\n"); + } + } + } + } + + cout << kTuplets.str(); +} + +} // namespace diff -Nru primesieve-6.3+ds/src/README.md primesieve-7.0+ds/src/README.md --- primesieve-6.3+ds/src/README.md 1970-01-01 00:00:00.000000000 +0000 +++ primesieve-7.0+ds/src/README.md 2018-06-08 08:51:41.000000000 +0000 @@ -0,0 +1,90 @@ +# C++ classes + +* **PrimeSieve** is a high level class that coordinates prime sieving. + It is used for printing and counting primes and for computing the nth + prime. PrimeSieve's main method is ```PrimeSieve::sieve(start, stop)``` + which sieves the primes inside the interval [start, stop]. + +* **ParallelSieve** launches multiple threads using ```std::async``` + and each thread sieves a part of the interval [start, stop] using a + PrimeSieve object. At the end all partial results are combined to get + the final result. + +* **Erat** is an implementation of the segmented sieve of Eratosthenes + using a bit array with 30 numbers per byte, each byte of the sieve array + holds the 8 offsets ```k = { 7, 11, 13, 17, 19, 23, 29, 31 }```. + Its main methods are ```addSievingPrime(prime)``` which is called + consecutively for all primes ≤ sqrt(n) and ```sieveSegment()``` which + sieves the next segment. Erat uses the EratSmall, EratMedium and + EratBig classes to cross-off multiples. + +* **EratSmall** is derived from Wheel. EratSmall is a segmented + sieve of Eratosthenes algorithm with a hard-coded modulo 30 wheel + that skips multiples of 2, 3 and 5. This algorithm is optimized + for small sieving primes that have many multiples in each + segment. EratSmall is a further optimized implementation of Achim + Flammenkamp's algorithm + [[1]](https://github.com/kimwalisch/primesieve/tree/master/src#references). + +* **EratMedium** is derived from Wheel. EratMedium is a segmented + sieve of Eratosthenes algorithm with a modulo 210 wheel that skips + multiples of 2, 3, 5 and 7. The wheel is implemented using a +  precomputed lookup table (```wheel210``` array from + ```Wheel.cpp```). This algorithm is optimized for medium sieving + primes with a few multiples per segment. + +* **EratBig** is derived from Wheel. EratBig is a segmented sieve of + Eratosthenes algorithm with Tomás Oliveira's improvement for big + sieving primes [[2]](https://github.com/kimwalisch/primesieve/tree/master/src#references) + and a modulo 210 wheel that skips multiples of 2, 3, 5 and 7. The + wheel is implemented using a precomputed lookup table (```wheel210``` + array from ```Wheel.cpp```). EratBig is optimized for big sieving + primes that have less than one multiple per segment. + +* **PreSieve** is used to pre-sieve multiples of small primes ≤ 19 + to speed up the sieve of Eratosthenes. Upon creation the + multiples of small primes are removed from a buffer. Later this + buffer is simply copied to the sieve array to remove (pre-sieve) + the multiples of small primes. + +* **SievingPrimes** is derived from Erat. The SievingPrimes class is used + to generate the sieving primes ≤ sqrt(stop). SievingPrimes is used + by the PrintPrimes and PrimeGenerator classes. + +* **PrintPrimes** is derived from Erat. PrintPrimes is used for printing + primes to stdout and for counting primes. After a segment has been + sieved (using Erat) PrintPrimes is used to reconstruct primes and prime + k-tuplets from 1 bits of the sieve array. + +* **PrimeGenerator** is derived from Erat. It generates the primes inside + [start, stop] and stores them in a vector. PrimeGenerator can fill a + vector gradually or at once. After the primes have been stored in the + vector primesieve::iterator iterates over the vector and returns the + primes. When there are no more primes left in the vector PrimeGenerator + generates new primes. + +* **primesieve::iterator** allows to easily iterate over primes. It +  provides ```next_prime()``` and ```prev_prime()``` methods. + primesieve::iterator is also used for storing primes in a vector + or an array. + +* **CpuInfo** is used to get the CPU's L1 and L2 cache sizes. The + best prime sieving performance is achieved using a sieve array + size that matches the CPU's L1 or L2 cache size (depending on the + CPU type). + +* **Wheel** factorization is used to skip multiples of small primes + ≤ 7 to speed up the sieve of Eratosthenes. The abstract Wheel class + is used to initialize sieving primes i.e. ```Wheel::addSievingPrime()``` + calculates the first multiple ≥ start of each sieving prime and the position + within the sieve array of that multiple. ```Wheel::unsetBit()``` is + used to cross-off a multiple (unset a bit) and to calculate the sieving + prime's next multiple. + +# References + +1. Achim Flammenkamp, "The Art of Prime Sieving", 1998.
+ https://wwwhomes.uni-bielefeld.de/achim/prime_sieve.html +2. Tomás Oliveira e Silva, "Fast implementation of the segmented + sieve of Eratosthenes", 2002.
+ http://www.ieeta.pt/~tos/software/prime_sieve.html diff -Nru primesieve-6.3+ds/src/SievingPrimes.cpp primesieve-7.0+ds/src/SievingPrimes.cpp --- primesieve-6.3+ds/src/SievingPrimes.cpp 1970-01-01 00:00:00.000000000 +0000 +++ primesieve-7.0+ds/src/SievingPrimes.cpp 2018-06-08 08:51:41.000000000 +0000 @@ -0,0 +1,93 @@ +/// +/// @file SievingPrimes.cpp +/// Generates the sieving primes up n^(1/2). +/// +/// Copyright (C) 2018 Kim Walisch, +/// +/// This file is distributed under the BSD License. See the COPYING +/// file in the top level directory. +/// + +#include +#include +#include +#include +#include + +#include +#include + +namespace primesieve { + +SievingPrimes::SievingPrimes(Erat* erat, PreSieve& preSieve) +{ + init(erat, preSieve); +} + +void SievingPrimes::init(Erat* erat, PreSieve& preSieve) +{ + Erat::init(preSieve.getMaxPrime() + 1, + isqrt(erat->getStop()), + erat->getSieveSize(), + preSieve); + + tinySieve(); +} + +/// Sieve up to n^(1/4) +void SievingPrimes::tinySieve() +{ + uint64_t n = isqrt(stop_); + tinySieve_.resize(n + 1, true); + + for (uint64_t i = 3; i * i <= n; i += 2) + if (tinySieve_[i]) + for (uint64_t j = i * i; j <= n; j += i * 2) + tinySieve_[j] = false; + + tinyIdx_ = start_; + tinyIdx_ += ~tinyIdx_ & 1; +} + +void SievingPrimes::fill() +{ + if (sieveIdx_ >= sieveSize_) + if (!sieveSegment()) + return; + + uint64_t num = 0; + uint64_t bits = littleendian_cast(&sieve_[sieveIdx_]); + sieveIdx_ += 8; + + for (; bits != 0; num++) + primes_[num] = nextPrime(&bits, low_); + + i_ = 0; + size_ = num; + low_ += 8 * 30; +} + +bool SievingPrimes::sieveSegment() +{ + if (hasNextSegment()) + { + sieveIdx_ = 0; + uint64_t high = segmentHigh_; + + for (uint64_t& i = tinyIdx_; i * i <= high; i += 2) + if (tinySieve_[i]) + addSievingPrime(i); + + Erat::sieveSegment(); + return true; + } + else + { + i_ = 0; + size_ = 1; + primes_[0] = ~0ull; + return false; + } +} + +} // namespace diff -Nru primesieve-6.3+ds/src/Wheel.cpp primesieve-7.0+ds/src/Wheel.cpp --- primesieve-6.3+ds/src/Wheel.cpp 1970-01-01 00:00:00.000000000 +0000 +++ primesieve-7.0+ds/src/Wheel.cpp 2018-06-08 08:51:41.000000000 +0000 @@ -0,0 +1,175 @@ +/// +/// @file Wheel.cpp +/// @brief Precomputed arrays for wheel factorization. +/// +/// Copyright (C) 2017 Kim Walisch, +/// +/// This file is distributed under the BSD License. See the COPYING +/// file in the top level directory. +/// + +#include +#include + +namespace primesieve { + +const WheelInit wheel30Init[30] = +{ + {1, 0}, {0, 0}, {5, 1}, {4, 1}, {3, 1}, {2, 1}, {1, 1}, {0, 1}, + {3, 2}, {2, 2}, {1, 2}, {0, 2}, {1, 3}, {0, 3}, {3, 4}, {2, 4}, + {1, 4}, {0, 4}, {1, 5}, {0, 5}, {3, 6}, {2, 6}, {1, 6}, {0, 6}, + {5, 7}, {4, 7}, {3, 7}, {2, 7}, {1, 7}, {0, 7} +}; + +const WheelInit wheel210Init[210] = +{ + {1, 0}, {0, 0}, {9, 1}, {8, 1}, {7, 1}, {6, 1}, {5, 1}, {4, 1}, + {3, 1}, {2, 1}, {1, 1}, {0, 1}, {1, 2}, {0, 2}, {3, 3}, {2, 3}, + {1, 3}, {0, 3}, {1, 4}, {0, 4}, {3, 5}, {2, 5}, {1, 5}, {0, 5}, + {5, 6}, {4, 6}, {3, 6}, {2, 6}, {1, 6}, {0, 6}, {1, 7}, {0, 7}, + {5, 8}, {4, 8}, {3, 8}, {2, 8}, {1, 8}, {0, 8}, {3, 9}, {2, 9}, + {1, 9}, {0, 9}, {1, 10}, {0, 10}, {3, 11}, {2, 11}, {1, 11}, {0, 11}, + {5, 12}, {4, 12}, {3, 12}, {2, 12}, {1, 12}, {0, 12}, {5, 13}, {4, 13}, + {3, 13}, {2, 13}, {1, 13}, {0, 13}, {1, 14}, {0, 14}, {5, 15}, {4, 15}, + {3, 15}, {2, 15}, {1, 15}, {0, 15}, {3, 16}, {2, 16}, {1, 16}, {0, 16}, + {1, 17}, {0, 17}, {5, 18}, {4, 18}, {3, 18}, {2, 18}, {1, 18}, {0, 18}, + {3, 19}, {2, 19}, {1, 19}, {0, 19}, {5, 20}, {4, 20}, {3, 20}, {2, 20}, + {1, 20}, {0, 20}, {7, 21}, {6, 21}, {5, 21}, {4, 21}, {3, 21}, {2, 21}, + {1, 21}, {0, 21}, {3, 22}, {2, 22}, {1, 22}, {0, 22}, {1, 23}, {0, 23}, + {3, 24}, {2, 24}, {1, 24}, {0, 24}, {1, 25}, {0, 25}, {3, 26}, {2, 26}, + {1, 26}, {0, 26}, {7, 27}, {6, 27}, {5, 27}, {4, 27}, {3, 27}, {2, 27}, + {1, 27}, {0, 27}, {5, 28}, {4, 28}, {3, 28}, {2, 28}, {1, 28}, {0, 28}, + {3, 29}, {2, 29}, {1, 29}, {0, 29}, {5, 30}, {4, 30}, {3, 30}, {2, 30}, + {1, 30}, {0, 30}, {1, 31}, {0, 31}, {3, 32}, {2, 32}, {1, 32}, {0, 32}, + {5, 33}, {4, 33}, {3, 33}, {2, 33}, {1, 33}, {0, 33}, {1, 34}, {0, 34}, + {5, 35}, {4, 35}, {3, 35}, {2, 35}, {1, 35}, {0, 35}, {5, 36}, {4, 36}, + {3, 36}, {2, 36}, {1, 36}, {0, 36}, {3, 37}, {2, 37}, {1, 37}, {0, 37}, + {1, 38}, {0, 38}, {3, 39}, {2, 39}, {1, 39}, {0, 39}, {5, 40}, {4, 40}, + {3, 40}, {2, 40}, {1, 40}, {0, 40}, {1, 41}, {0, 41}, {5, 42}, {4, 42}, + {3, 42}, {2, 42}, {1, 42}, {0, 42}, {3, 43}, {2, 43}, {1, 43}, {0, 43}, + {1, 44}, {0, 44}, {3, 45}, {2, 45}, {1, 45}, {0, 45}, {1, 46}, {0, 46}, + {9, 47}, {8, 47}, {7, 47}, {6, 47}, {5, 47}, {4, 47}, {3, 47}, {2, 47}, + {1, 47}, {0, 47} +}; + +const WheelElement wheel30[8*8] = +{ + { BIT0, 6, 1, 1 }, { BIT4, 4, 1, 1 }, { BIT3, 2, 0, 1 }, { BIT7, 4, 1, 1 }, + { BIT6, 2, 1, 1 }, { BIT2, 4, 1, 1 }, { BIT1, 6, 1, 1 }, { BIT5, 2, 1, -7 }, + { BIT1, 6, 2, 1 }, { BIT3, 4, 1, 1 }, { BIT7, 2, 1, 1 }, { BIT5, 4, 2, 1 }, + { BIT0, 2, 0, 1 }, { BIT6, 4, 2, 1 }, { BIT2, 6, 2, 1 }, { BIT4, 2, 1, -7 }, + { BIT2, 6, 2, 1 }, { BIT7, 4, 2, 1 }, { BIT5, 2, 1, 1 }, { BIT4, 4, 2, 1 }, + { BIT1, 2, 1, 1 }, { BIT0, 4, 1, 1 }, { BIT6, 6, 3, 1 }, { BIT3, 2, 1, -7 }, + { BIT3, 6, 3, 1 }, { BIT6, 4, 3, 1 }, { BIT0, 2, 1, 1 }, { BIT1, 4, 2, 1 }, + { BIT4, 2, 1, 1 }, { BIT5, 4, 2, 1 }, { BIT7, 6, 4, 1 }, { BIT2, 2, 1, -7 }, + { BIT4, 6, 4, 1 }, { BIT2, 4, 2, 1 }, { BIT6, 2, 2, 1 }, { BIT0, 4, 2, 1 }, + { BIT5, 2, 1, 1 }, { BIT7, 4, 3, 1 }, { BIT3, 6, 4, 1 }, { BIT1, 2, 1, -7 }, + { BIT5, 6, 5, 1 }, { BIT1, 4, 3, 1 }, { BIT2, 2, 1, 1 }, { BIT6, 4, 3, 1 }, + { BIT7, 2, 2, 1 }, { BIT3, 4, 3, 1 }, { BIT4, 6, 5, 1 }, { BIT0, 2, 1, -7 }, + { BIT6, 6, 6, 1 }, { BIT5, 4, 4, 1 }, { BIT4, 2, 2, 1 }, { BIT3, 4, 4, 1 }, + { BIT2, 2, 2, 1 }, { BIT1, 4, 4, 1 }, { BIT0, 6, 5, 1 }, { BIT7, 2, 2, -7 }, + { BIT7, 6, 1, 1 }, { BIT0, 4, 0, 1 }, { BIT1, 2, 0, 1 }, { BIT2, 4, 0, 1 }, + { BIT3, 2, 0, 1 }, { BIT4, 4, 0, 1 }, { BIT5, 6, 0, 1 }, { BIT6, 2, 0, -7 } +}; + +const WheelElement wheel210[48*8] = +{ + { BIT0, 10, 2, 1 }, { BIT3, 2, 0, 1 }, { BIT7, 4, 1, 1 }, { BIT6, 2, 1, 1 }, + { BIT2, 4, 1, 1 }, { BIT1, 6, 1, 1 }, { BIT5, 2, 1, 1 }, { BIT0, 6, 1, 1 }, + { BIT4, 4, 1, 1 }, { BIT3, 2, 0, 1 }, { BIT7, 4, 1, 1 }, { BIT6, 6, 2, 1 }, + { BIT1, 6, 1, 1 }, { BIT5, 2, 1, 1 }, { BIT0, 6, 1, 1 }, { BIT4, 4, 1, 1 }, + { BIT3, 2, 0, 1 }, { BIT7, 6, 2, 1 }, { BIT2, 4, 1, 1 }, { BIT1, 6, 1, 1 }, + { BIT5, 8, 2, 1 }, { BIT4, 4, 1, 1 }, { BIT3, 2, 0, 1 }, { BIT7, 4, 1, 1 }, + { BIT6, 2, 1, 1 }, { BIT2, 4, 1, 1 }, { BIT1, 8, 2, 1 }, { BIT0, 6, 1, 1 }, + { BIT4, 4, 1, 1 }, { BIT3, 6, 1, 1 }, { BIT6, 2, 1, 1 }, { BIT2, 4, 1, 1 }, + { BIT1, 6, 1, 1 }, { BIT5, 2, 1, 1 }, { BIT0, 6, 1, 1 }, { BIT4, 6, 1, 1 }, + { BIT7, 4, 1, 1 }, { BIT6, 2, 1, 1 }, { BIT2, 4, 1, 1 }, { BIT1, 6, 1, 1 }, + { BIT5, 2, 1, 1 }, { BIT0, 6, 1, 1 }, { BIT4, 4, 1, 1 }, { BIT3, 2, 0, 1 }, + { BIT7, 4, 1, 1 }, { BIT6, 2, 1, 1 }, { BIT2, 10, 2, 1 }, { BIT5, 2, 1, -47 }, + { BIT1, 10, 3, 1 }, { BIT7, 2, 1, 1 }, { BIT5, 4, 2, 1 }, { BIT0, 2, 0, 1 }, + { BIT6, 4, 2, 1 }, { BIT2, 6, 2, 1 }, { BIT4, 2, 1, 1 }, { BIT1, 6, 2, 1 }, + { BIT3, 4, 1, 1 }, { BIT7, 2, 1, 1 }, { BIT5, 4, 2, 1 }, { BIT0, 6, 2, 1 }, + { BIT2, 6, 2, 1 }, { BIT4, 2, 1, 1 }, { BIT1, 6, 2, 1 }, { BIT3, 4, 1, 1 }, + { BIT7, 2, 1, 1 }, { BIT5, 6, 2, 1 }, { BIT6, 4, 2, 1 }, { BIT2, 6, 2, 1 }, + { BIT4, 8, 3, 1 }, { BIT3, 4, 1, 1 }, { BIT7, 2, 1, 1 }, { BIT5, 4, 2, 1 }, + { BIT0, 2, 0, 1 }, { BIT6, 4, 2, 1 }, { BIT2, 8, 3, 1 }, { BIT1, 6, 2, 1 }, + { BIT3, 4, 1, 1 }, { BIT7, 6, 3, 1 }, { BIT0, 2, 0, 1 }, { BIT6, 4, 2, 1 }, + { BIT2, 6, 2, 1 }, { BIT4, 2, 1, 1 }, { BIT1, 6, 2, 1 }, { BIT3, 6, 2, 1 }, + { BIT5, 4, 2, 1 }, { BIT0, 2, 0, 1 }, { BIT6, 4, 2, 1 }, { BIT2, 6, 2, 1 }, + { BIT4, 2, 1, 1 }, { BIT1, 6, 2, 1 }, { BIT3, 4, 1, 1 }, { BIT7, 2, 1, 1 }, + { BIT5, 4, 2, 1 }, { BIT0, 2, 0, 1 }, { BIT6, 10, 4, 1 }, { BIT4, 2, 1, -47 }, + { BIT2, 10, 4, 1 }, { BIT5, 2, 1, 1 }, { BIT4, 4, 2, 1 }, { BIT1, 2, 1, 1 }, + { BIT0, 4, 1, 1 }, { BIT6, 6, 3, 1 }, { BIT3, 2, 1, 1 }, { BIT2, 6, 2, 1 }, + { BIT7, 4, 2, 1 }, { BIT5, 2, 1, 1 }, { BIT4, 4, 2, 1 }, { BIT1, 6, 2, 1 }, + { BIT6, 6, 3, 1 }, { BIT3, 2, 1, 1 }, { BIT2, 6, 2, 1 }, { BIT7, 4, 2, 1 }, + { BIT5, 2, 1, 1 }, { BIT4, 6, 3, 1 }, { BIT0, 4, 1, 1 }, { BIT6, 6, 3, 1 }, + { BIT3, 8, 3, 1 }, { BIT7, 4, 2, 1 }, { BIT5, 2, 1, 1 }, { BIT4, 4, 2, 1 }, + { BIT1, 2, 1, 1 }, { BIT0, 4, 1, 1 }, { BIT6, 8, 4, 1 }, { BIT2, 6, 2, 1 }, + { BIT7, 4, 2, 1 }, { BIT5, 6, 3, 1 }, { BIT1, 2, 1, 1 }, { BIT0, 4, 1, 1 }, + { BIT6, 6, 3, 1 }, { BIT3, 2, 1, 1 }, { BIT2, 6, 2, 1 }, { BIT7, 6, 3, 1 }, + { BIT4, 4, 2, 1 }, { BIT1, 2, 1, 1 }, { BIT0, 4, 1, 1 }, { BIT6, 6, 3, 1 }, + { BIT3, 2, 1, 1 }, { BIT2, 6, 2, 1 }, { BIT7, 4, 2, 1 }, { BIT5, 2, 1, 1 }, + { BIT4, 4, 2, 1 }, { BIT1, 2, 1, 1 }, { BIT0, 10, 4, 1 }, { BIT3, 2, 1, -47 }, + { BIT3, 10, 6, 1 }, { BIT0, 2, 1, 1 }, { BIT1, 4, 2, 1 }, { BIT4, 2, 1, 1 }, + { BIT5, 4, 2, 1 }, { BIT7, 6, 4, 1 }, { BIT2, 2, 1, 1 }, { BIT3, 6, 3, 1 }, + { BIT6, 4, 3, 1 }, { BIT0, 2, 1, 1 }, { BIT1, 4, 2, 1 }, { BIT4, 6, 3, 1 }, + { BIT7, 6, 4, 1 }, { BIT2, 2, 1, 1 }, { BIT3, 6, 3, 1 }, { BIT6, 4, 3, 1 }, + { BIT0, 2, 1, 1 }, { BIT1, 6, 3, 1 }, { BIT5, 4, 2, 1 }, { BIT7, 6, 4, 1 }, + { BIT2, 8, 4, 1 }, { BIT6, 4, 3, 1 }, { BIT0, 2, 1, 1 }, { BIT1, 4, 2, 1 }, + { BIT4, 2, 1, 1 }, { BIT5, 4, 2, 1 }, { BIT7, 8, 5, 1 }, { BIT3, 6, 3, 1 }, + { BIT6, 4, 3, 1 }, { BIT0, 6, 3, 1 }, { BIT4, 2, 1, 1 }, { BIT5, 4, 2, 1 }, + { BIT7, 6, 4, 1 }, { BIT2, 2, 1, 1 }, { BIT3, 6, 3, 1 }, { BIT6, 6, 4, 1 }, + { BIT1, 4, 2, 1 }, { BIT4, 2, 1, 1 }, { BIT5, 4, 2, 1 }, { BIT7, 6, 4, 1 }, + { BIT2, 2, 1, 1 }, { BIT3, 6, 3, 1 }, { BIT6, 4, 3, 1 }, { BIT0, 2, 1, 1 }, + { BIT1, 4, 2, 1 }, { BIT4, 2, 1, 1 }, { BIT5, 10, 6, 1 }, { BIT2, 2, 1, -47 }, + { BIT4, 10, 6, 1 }, { BIT6, 2, 2, 1 }, { BIT0, 4, 2, 1 }, { BIT5, 2, 1, 1 }, + { BIT7, 4, 3, 1 }, { BIT3, 6, 4, 1 }, { BIT1, 2, 1, 1 }, { BIT4, 6, 4, 1 }, + { BIT2, 4, 2, 1 }, { BIT6, 2, 2, 1 }, { BIT0, 4, 2, 1 }, { BIT5, 6, 4, 1 }, + { BIT3, 6, 4, 1 }, { BIT1, 2, 1, 1 }, { BIT4, 6, 4, 1 }, { BIT2, 4, 2, 1 }, + { BIT6, 2, 2, 1 }, { BIT0, 6, 3, 1 }, { BIT7, 4, 3, 1 }, { BIT3, 6, 4, 1 }, + { BIT1, 8, 5, 1 }, { BIT2, 4, 2, 1 }, { BIT6, 2, 2, 1 }, { BIT0, 4, 2, 1 }, + { BIT5, 2, 1, 1 }, { BIT7, 4, 3, 1 }, { BIT3, 8, 5, 1 }, { BIT4, 6, 4, 1 }, + { BIT2, 4, 2, 1 }, { BIT6, 6, 4, 1 }, { BIT5, 2, 1, 1 }, { BIT7, 4, 3, 1 }, + { BIT3, 6, 4, 1 }, { BIT1, 2, 1, 1 }, { BIT4, 6, 4, 1 }, { BIT2, 6, 4, 1 }, + { BIT0, 4, 2, 1 }, { BIT5, 2, 1, 1 }, { BIT7, 4, 3, 1 }, { BIT3, 6, 4, 1 }, + { BIT1, 2, 1, 1 }, { BIT4, 6, 4, 1 }, { BIT2, 4, 2, 1 }, { BIT6, 2, 2, 1 }, + { BIT0, 4, 2, 1 }, { BIT5, 2, 1, 1 }, { BIT7, 10, 7, 1 }, { BIT1, 2, 1, -47 }, + { BIT5, 10, 8, 1 }, { BIT2, 2, 1, 1 }, { BIT6, 4, 3, 1 }, { BIT7, 2, 2, 1 }, + { BIT3, 4, 3, 1 }, { BIT4, 6, 5, 1 }, { BIT0, 2, 1, 1 }, { BIT5, 6, 5, 1 }, + { BIT1, 4, 3, 1 }, { BIT2, 2, 1, 1 }, { BIT6, 4, 3, 1 }, { BIT7, 6, 5, 1 }, + { BIT4, 6, 5, 1 }, { BIT0, 2, 1, 1 }, { BIT5, 6, 5, 1 }, { BIT1, 4, 3, 1 }, + { BIT2, 2, 1, 1 }, { BIT6, 6, 5, 1 }, { BIT3, 4, 3, 1 }, { BIT4, 6, 5, 1 }, + { BIT0, 8, 6, 1 }, { BIT1, 4, 3, 1 }, { BIT2, 2, 1, 1 }, { BIT6, 4, 3, 1 }, + { BIT7, 2, 2, 1 }, { BIT3, 4, 3, 1 }, { BIT4, 8, 6, 1 }, { BIT5, 6, 5, 1 }, + { BIT1, 4, 3, 1 }, { BIT2, 6, 4, 1 }, { BIT7, 2, 2, 1 }, { BIT3, 4, 3, 1 }, + { BIT4, 6, 5, 1 }, { BIT0, 2, 1, 1 }, { BIT5, 6, 5, 1 }, { BIT1, 6, 4, 1 }, + { BIT6, 4, 3, 1 }, { BIT7, 2, 2, 1 }, { BIT3, 4, 3, 1 }, { BIT4, 6, 5, 1 }, + { BIT0, 2, 1, 1 }, { BIT5, 6, 5, 1 }, { BIT1, 4, 3, 1 }, { BIT2, 2, 1, 1 }, + { BIT6, 4, 3, 1 }, { BIT7, 2, 2, 1 }, { BIT3, 10, 8, 1 }, { BIT0, 2, 1, -47 }, + { BIT6, 10,10, 1 }, { BIT4, 2, 2, 1 }, { BIT3, 4, 4, 1 }, { BIT2, 2, 2, 1 }, + { BIT1, 4, 4, 1 }, { BIT0, 6, 5, 1 }, { BIT7, 2, 2, 1 }, { BIT6, 6, 6, 1 }, + { BIT5, 4, 4, 1 }, { BIT4, 2, 2, 1 }, { BIT3, 4, 4, 1 }, { BIT2, 6, 6, 1 }, + { BIT0, 6, 5, 1 }, { BIT7, 2, 2, 1 }, { BIT6, 6, 6, 1 }, { BIT5, 4, 4, 1 }, + { BIT4, 2, 2, 1 }, { BIT3, 6, 6, 1 }, { BIT1, 4, 4, 1 }, { BIT0, 6, 5, 1 }, + { BIT7, 8, 8, 1 }, { BIT5, 4, 4, 1 }, { BIT4, 2, 2, 1 }, { BIT3, 4, 4, 1 }, + { BIT2, 2, 2, 1 }, { BIT1, 4, 4, 1 }, { BIT0, 8, 7, 1 }, { BIT6, 6, 6, 1 }, + { BIT5, 4, 4, 1 }, { BIT4, 6, 6, 1 }, { BIT2, 2, 2, 1 }, { BIT1, 4, 4, 1 }, + { BIT0, 6, 5, 1 }, { BIT7, 2, 2, 1 }, { BIT6, 6, 6, 1 }, { BIT5, 6, 6, 1 }, + { BIT3, 4, 4, 1 }, { BIT2, 2, 2, 1 }, { BIT1, 4, 4, 1 }, { BIT0, 6, 5, 1 }, + { BIT7, 2, 2, 1 }, { BIT6, 6, 6, 1 }, { BIT5, 4, 4, 1 }, { BIT4, 2, 2, 1 }, + { BIT3, 4, 4, 1 }, { BIT2, 2, 2, 1 }, { BIT1, 10, 9, 1 }, { BIT7, 2, 2, -47 }, + { BIT7, 10, 1, 1 }, { BIT1, 2, 0, 1 }, { BIT2, 4, 0, 1 }, { BIT3, 2, 0, 1 }, + { BIT4, 4, 0, 1 }, { BIT5, 6, 0, 1 }, { BIT6, 2, 0, 1 }, { BIT7, 6, 1, 1 }, + { BIT0, 4, 0, 1 }, { BIT1, 2, 0, 1 }, { BIT2, 4, 0, 1 }, { BIT3, 6, 0, 1 }, + { BIT5, 6, 0, 1 }, { BIT6, 2, 0, 1 }, { BIT7, 6, 1, 1 }, { BIT0, 4, 0, 1 }, + { BIT1, 2, 0, 1 }, { BIT2, 6, 0, 1 }, { BIT4, 4, 0, 1 }, { BIT5, 6, 0, 1 }, + { BIT6, 8, 1, 1 }, { BIT0, 4, 0, 1 }, { BIT1, 2, 0, 1 }, { BIT2, 4, 0, 1 }, + { BIT3, 2, 0, 1 }, { BIT4, 4, 0, 1 }, { BIT5, 8, 0, 1 }, { BIT7, 6, 1, 1 }, + { BIT0, 4, 0, 1 }, { BIT1, 6, 0, 1 }, { BIT3, 2, 0, 1 }, { BIT4, 4, 0, 1 }, + { BIT5, 6, 0, 1 }, { BIT6, 2, 0, 1 }, { BIT7, 6, 1, 1 }, { BIT0, 6, 0, 1 }, + { BIT2, 4, 0, 1 }, { BIT3, 2, 0, 1 }, { BIT4, 4, 0, 1 }, { BIT5, 6, 0, 1 }, + { BIT6, 2, 0, 1 }, { BIT7, 6, 1, 1 }, { BIT0, 4, 0, 1 }, { BIT1, 2, 0, 1 }, + { BIT2, 4, 0, 1 }, { BIT3, 2, 0, 1 }, { BIT4, 10, 0, 1 }, { BIT6, 2, 0, -47 } +}; + +} // namespace diff -Nru primesieve-6.3+ds/test/atomic.cpp primesieve-7.0+ds/test/atomic.cpp --- primesieve-6.3+ds/test/atomic.cpp 2017-11-18 12:38:21.000000000 +0000 +++ primesieve-7.0+ds/test/atomic.cpp 2018-06-08 08:51:41.000000000 +0000 @@ -2,7 +2,7 @@ /// @file atomic.cpp /// @brief Test std::atomic thread synchronization. /// We use std::atomic for thread synchronization in -/// ParallelPrimeSieve.cpp. +/// ParallelSieve.cpp. /// /// Copyright (C) 2017 Kim Walisch, /// diff -Nru primesieve-6.3+ds/test/calculator.cpp primesieve-7.0+ds/test/calculator.cpp --- primesieve-6.3+ds/test/calculator.cpp 1970-01-01 00:00:00.000000000 +0000 +++ primesieve-7.0+ds/test/calculator.cpp 2018-06-08 08:51:41.000000000 +0000 @@ -0,0 +1,79 @@ +/// +/// @file calculator.cpp +/// @brief test program for calculator.hpp +/// +/// Copyright (C) 2018 Kim Walisch, +/// +/// This file is distributed under the BSD License. See the COPYING +/// file in the top level directory. +/// + +#include + +#include +#include +#include +#include +#include + +#define STR1(s) #s +#define TOSTRING(s) STR1(s) + +/// Test expressions +#define EXPR1 45345 + 0 + 0xdf234 - 1000 % 7 +#define EXPR2 (0 + 0xdf234 - 1000) * 3 / 2 % 999 +#define EXPR3 1 << 16 +#define EXPR4 (0 + ~(0xdf234 & 1000) * 3) / -2 +#define EXPR5 ((1 << 16) + (1 << 16)) >> 0X5 +#define EXPR6 1+(((2+(3+(4+(5+6)* -7)/8))&127)<<1) *-3 +#define EXPR7 100000000 + (1 << 16) + (1 << 16) +#define EXPR8 1-~1 +#define EXPR9 1- ~1*0xfFa/( ((((8+(6|(4 *(2*(1)*3)*5)|7)+9))))) +#define EXPRa ((12|13)<<8)>>((1|127) %10&(31+7)) +#define EXPRb ((((((((((5)))))) ))))- ((((((((( 6))))))))) + +using namespace std; + +template +void compare(T result, const string& str) +{ + T r = calculator::eval(str); + cout << (r == result ? "Correct: " : "Error: "); + cout << setw(50) << str << " = " << setw(10) << r; + if (r != result) + { + cout << " != " << result; + exit(1); + } + cout << endl; +} + +int main() +{ + cout.setf(ios::left); + + compare(EXPR1, TOSTRING(EXPR1)); + compare(EXPR2, TOSTRING(EXPR2)); + compare(EXPR3, TOSTRING(EXPR3)); + compare(EXPR4, TOSTRING(EXPR4)); + compare(EXPR5, TOSTRING(EXPR5)); + compare(EXPR6, TOSTRING(EXPR6)); + compare(EXPR7, TOSTRING(EXPR7)); + compare(EXPR8, TOSTRING(EXPR8)); + compare(EXPR9, TOSTRING(EXPR9)); + compare(EXPRa, TOSTRING(EXPRa)); + compare(EXPRb, TOSTRING(EXPRb)); + + compare(calculator::eval("1e18"), "1000000000000000000"); + compare(calculator::eval("3e18"), "3000000000000000000"); + compare(calculator::eval("10^0"), "1"); + compare(calculator::eval("10^1"), "10"); + compare(calculator::eval("37^2"), "1369"); + compare(calculator::eval("101^3"), "1030301"); + compare(calculator::eval("3^30"), "205891132094649"); + compare(calculator::eval("2^62-1"), "4611686018427387903"); + + cout << "All tests passed successfully!" << endl; + + return 0; +} diff -Nru primesieve-6.3+ds/test/CMakeLists.txt primesieve-7.0+ds/test/CMakeLists.txt --- primesieve-6.3+ds/test/CMakeLists.txt 2017-11-18 12:38:21.000000000 +0000 +++ primesieve-7.0+ds/test/CMakeLists.txt 2018-06-08 08:51:41.000000000 +0000 @@ -1,7 +1,9 @@ +enable_language(C) file(GLOB files "*.cpp" "*.c") + foreach(file ${files}) get_filename_component(binary_name ${file} NAME_WE) add_executable(${binary_name} ${file}) - target_link_libraries(${binary_name} libprimesieve) + target_link_libraries(${binary_name} primesieve::primesieve Threads::Threads ${LIBATOMIC}) add_test(NAME ${binary_name} COMMAND ${binary_name}) endforeach() diff -Nru primesieve-6.3+ds/test/count_primes1.cpp primesieve-7.0+ds/test/count_primes1.cpp --- primesieve-6.3+ds/test/count_primes1.cpp 2017-11-18 12:38:21.000000000 +0000 +++ primesieve-7.0+ds/test/count_primes1.cpp 2018-06-08 08:51:41.000000000 +0000 @@ -2,13 +2,13 @@ /// @file count_primes1.cpp /// @brief Count the primes up to 10^9. /// -/// Copyright (C) 2017 Kim Walisch, +/// Copyright (C) 2018 Kim Walisch, /// /// This file is distributed under the BSD License. See the COPYING /// file in the top level directory. /// -#include +#include #include #include @@ -43,15 +43,15 @@ int main() { cout << left; - ParallelPrimeSieve pps; - pps.setStart(0); - pps.setStop(0); + ParallelSieve ps; + ps.setStart(0); + ps.setStop(0); uint64_t count = 0; // pi(x) with x = 10^i for i = 1 to 9 for (int i = 1; i <= 9; i++) { - count += pps.countPrimes(pps.getStop() + 1, (uint64_t) pow(10.0, i)); + count += ps.countPrimes(ps.getStop() + 1, (uint64_t) pow(10.0, i)); cout << "pi(10^" << i << ") = " << setw(12) << count; check(count == pix[i - 1]); } diff -Nru primesieve-6.3+ds/test/count_primes2.cpp primesieve-7.0+ds/test/count_primes2.cpp --- primesieve-6.3+ds/test/count_primes2.cpp 2017-11-18 12:38:21.000000000 +0000 +++ primesieve-7.0+ds/test/count_primes2.cpp 2018-06-08 08:51:41.000000000 +0000 @@ -1,34 +1,34 @@ /// /// @file count_primes2.cpp -/// @brief Count the primes within [10^i, 10^i + 10^8] for i = 12 to 19 +/// @brief Count the primes within [10^i, 10^i + 10^8] +/// for i = 12 to 19 /// -/// Copyright (C) 2017 Kim Walisch, +/// Copyright (C) 2018 Kim Walisch, /// /// This file is distributed under the BSD License. See the COPYING /// file in the top level directory. /// -#include +#include #include -#include -#include +#include #include #include +#include +#include using namespace std; using namespace primesieve; -const uint64_t pix[8] = +const array pix = { 3618282, // pi[10^12, 10^12+10^8] 3342093, // pi[10^13, 10^13+10^8] 3102679, // pi[10^14, 10^14+10^8] 2893937, // pi[10^15, 10^15+10^8] 2714904, // pi[10^16, 10^16+10^8] - 2555873, // pi[10^17, 10^17+10^8] - 2414886, // pi[10^18, 10^18+10^8] - 2285232 // pi[10^19, 10^19+10^8] + 2555873 // pi[10^17, 10^17+10^8] }; void check(bool OK) @@ -41,18 +41,16 @@ int main() { cout << left; - ParallelPrimeSieve p; - p.setFlags(p.COUNT_PRIMES | p.PRINT_STATUS); - for (int i = 0; i <= 7; i++) + for (size_t i = 0; i < pix.size(); i++) { - int j = i + 12; + size_t j = i + 12; cout << "Sieving the primes within [10^" << j << ", 10^" << j << " + 10^8]" << endl; - p.setStart((uint64_t) pow(10.0, j)); - p.setStop(p.getStart() + (uint64_t) 1e8); - p.sieve(); - cout << "\rPrime count: " << setw(7) << p.getPrimeCount(); - check(p.getPrimeCount() == pix[i]); + uint64_t start = (uint64_t) pow(10.0, j); + uint64_t stop = start + (uint64_t) 1e8; + uint64_t count = count_primes(start, stop); + cout << "\rPrime count: " << setw(7) << count; + check(count == pix[i]); } cout << endl; diff -Nru primesieve-6.3+ds/test/count_primes3.cpp primesieve-7.0+ds/test/count_primes3.cpp --- primesieve-6.3+ds/test/count_primes3.cpp 2017-11-18 12:38:21.000000000 +0000 +++ primesieve-7.0+ds/test/count_primes3.cpp 2018-06-08 08:51:41.000000000 +0000 @@ -1,6 +1,7 @@ /// /// @file count_primes3.cpp -/// @brief Count the primes within [10^13, 10^13 + 5*10^9] randomly +/// @brief Count the primes within [10^12, 10^12 + 10^9] +/// using random sized intervals. /// /// Copyright (C) 2017 Kim Walisch, /// @@ -8,7 +9,7 @@ /// file in the top level directory. /// -#include +#include #include #include @@ -28,36 +29,33 @@ int main() { - cout << "Sieving the primes within [10^13, 10^13 + 5*10^9] randomly" << endl; + cout << "Sieving the primes within [10^12, 10^12 + 10^9] randomly" << endl; - uint64_t maxDist = (uint64_t) 2e7; - uint64_t lowerBound = (uint64_t) 1e13; - uint64_t upperBound = lowerBound + (uint64_t) 5e9; uint64_t count = 0; - - ParallelPrimeSieve p; - p.setStart(lowerBound - 1); - p.setStop(lowerBound - 1); + uint64_t maxDist = (uint64_t) 1e7; + uint64_t lowerBound = (uint64_t) 1e12; + uint64_t upperBound = lowerBound + (uint64_t) 1e9; + uint64_t start = lowerBound - 1; + uint64_t stop = start; random_device rd; mt19937 gen(rd()); uniform_int_distribution dist(0, maxDist); - while (p.getStop() < upperBound) + while (stop < upperBound) { - p.setStart(p.getStop() + 1); - p.setStop(min(p.getStart() + dist(gen), upperBound)); - p.setSieveSize(1 << (dist(gen) % 13)); - p.sieve(); - count += p.getPrimeCount(); + start = stop + 1; + stop = min(start + dist(gen), upperBound); + set_sieve_size(1 << (dist(gen) % 13)); + count += count_primes(start, stop); cout << "\rRemaining chunk: " << "\rRemaining chunk: " - << upperBound - p.getStop() << flush; + << upperBound - stop << flush; } cout << endl << "Prime count: " << count; - check(count == 167038410); + check(count == 36190991); cout << endl; cout << "Test passed successfully!" << endl; diff -Nru primesieve-6.3+ds/test/isqrt_constexpr.cpp primesieve-7.0+ds/test/isqrt_constexpr.cpp --- primesieve-6.3+ds/test/isqrt_constexpr.cpp 1970-01-01 00:00:00.000000000 +0000 +++ primesieve-7.0+ds/test/isqrt_constexpr.cpp 2018-06-08 08:51:41.000000000 +0000 @@ -0,0 +1,119 @@ +/// +/// @file isqrt_constexpr.cpp +/// @brief Test compile time square root function. +/// +/// Copyright (C) 2018 Kim Walisch, +/// +/// This file is distributed under the BSD License. See the COPYING +/// file in the top level directory. +/// + +#include + +#include +#include +#include + +using namespace std; +using namespace primesieve; + +#if defined(BAD_ISQRT) + +/// The following compile time integer square root function +/// has a recursion depth of O(sqrt(n)). This is very bad, the +/// stack will explose if you try to compute the square root +/// of a number > 10^9. Furthermore constexpr recursion depth +/// is limited by the compiler even more e.g. both GCC and +/// Clang currently limit constexpr recursion depth to 512. +/// +/// The nasty thing is that GCC and Clang start calculating +/// constexpr functions at compile time but once the function +/// reaches a recursion depth > 512, GCC and Clang will stop +/// the compile time calculation and instead compute the +/// function at run-time. +/// +/// Because of this you cannot easily tell if your constexpr +/// function was evaluated at compile time or at run-time. +/// But you can use static_assert to test whether your constexpr +/// function is calculated at compile time or at runtime. +/// The code below will not compile with the compiler error +/// message telling you the maximum recursion depth has been +/// exceeded. + +template +constexpr T bad_isqrt(T sq, T dlt, T value) +{ + return sq > value ? (dlt >> 1) - 1 + : bad_isqrt(sq + dlt, dlt + 2, value); +} + +template +constexpr T bad_isqrt(T value) +{ + return bad_isqrt(1, 3, value); +} + +static_assert(bad_isqrt(100000000) == 10000, "bad_isqrt(10^8) failed!"); + +#endif + +int main() +{ + static_assert(ctSqrt(0) == 0, "ctSqrt(0) failed!"); + static_assert(ctSqrt(1) == 1, "ctSqrt(1) failed!"); + static_assert(ctSqrt(2) == 1, "ctSqrt(2) failed!"); + static_assert(ctSqrt(3) == 1, "ctSqrt(3) failed!"); + static_assert(ctSqrt(4) == 2, "ctSqrt(4) failed!"); + static_assert(ctSqrt(5) == 2, "ctSqrt(5) failed!"); + static_assert(ctSqrt(6) == 2, "ctSqrt(6) failed!"); + static_assert(ctSqrt(7) == 2, "ctSqrt(7) failed!"); + static_assert(ctSqrt(8) == 2, "ctSqrt(8) failed!"); + static_assert(ctSqrt(9) == 3, "ctSqrt(9) failed!"); + static_assert(ctSqrt(10) == 3, "ctSqrt(10) failed!"); + static_assert(ctSqrt(11) == 3, "ctSqrt(11) failed!"); + static_assert(ctSqrt(12) == 3, "ctSqrt(12) failed!"); + static_assert(ctSqrt(13) == 3, "ctSqrt(13) failed!"); + static_assert(ctSqrt(14) == 3, "ctSqrt(14) failed!"); + static_assert(ctSqrt(15) == 3, "ctSqrt(15) failed!"); + static_assert(ctSqrt(16) == 4, "ctSqrt(16) failed!"); + static_assert(ctSqrt(17) == 4, "ctSqrt(17) failed!"); + static_assert(ctSqrt(18) == 4, "ctSqrt(18) failed!"); + static_assert(ctSqrt(19) == 4, "ctSqrt(19) failed!"); + static_assert(ctSqrt(20) == 4, "ctSqrt(20) failed!"); + static_assert(ctSqrt(21) == 4, "ctSqrt(21) failed!"); + static_assert(ctSqrt(22) == 4, "ctSqrt(22) failed!"); + static_assert(ctSqrt(23) == 4, "ctSqrt(23) failed!"); + static_assert(ctSqrt(24) == 4, "ctSqrt(24) failed!"); + static_assert(ctSqrt(25) == 5, "ctSqrt(25) failed!"); + static_assert(ctSqrt(26) == 5, "ctSqrt(26) failed!"); + static_assert(ctSqrt(27) == 5, "ctSqrt(27) failed!"); + static_assert(ctSqrt(28) == 5, "ctSqrt(28) failed!"); + static_assert(ctSqrt(29) == 5, "ctSqrt(29) failed!"); + static_assert(ctSqrt(30) == 5, "ctSqrt(30) failed!"); + static_assert(ctSqrt(31) == 5, "ctSqrt(31) failed!"); + static_assert(ctSqrt(32) == 5, "ctSqrt(32) failed!"); + static_assert(ctSqrt(33) == 5, "ctSqrt(33) failed!"); + static_assert(ctSqrt(34) == 5, "ctSqrt(34) failed!"); + static_assert(ctSqrt(35) == 5, "ctSqrt(35) failed!"); + static_assert(ctSqrt(36) == 6, "ctSqrt(36) failed!"); + static_assert(ctSqrt(37) == 6, "ctSqrt(37) failed!"); + static_assert(ctSqrt(38) == 6, "ctSqrt(38) failed!"); + static_assert(ctSqrt(39) == 6, "ctSqrt(39) failed!"); + + static_assert(ctSqrt(9223372037000249999ull) == 3037000499ull, "ctSqrt(3037000500^2-1) failed!"); + static_assert(ctSqrt(9223372037000250000ull) == 3037000500ull, "ctSqrt(3037000500^2) failed!"); + static_assert(ctSqrt(9223372037000250001ull) == 3037000500ull, "ctSqrt(3037000500^2+1) failed!"); + + static_assert(ctSqrt(std::numeric_limits::max()) == 11, "ctSqrt(2^7-1) failed!"); + static_assert(ctSqrt(std::numeric_limits::max()) == 15, "ctSqrt(2^8-1) failed!"); + static_assert(ctSqrt(std::numeric_limits::max()) == 181, "ctSqrt(2^15-1) failed!"); + static_assert(ctSqrt(std::numeric_limits::max()) == 255, "ctSqrt(2^16-1) failed!"); + static_assert(ctSqrt(std::numeric_limits::max()) == 46340, "ctSqrt(2^31-1) failed!"); + static_assert(ctSqrt(std::numeric_limits::max()) == 65535, "ctSqrt(2^32-1) failed!"); + static_assert(ctSqrt(std::numeric_limits::max()) == 3037000499ll, "ctSqrt(2^63-1) failed!"); + static_assert(ctSqrt(std::numeric_limits::max()) == 4294967295ull, "ctSqrt(2^64-1) failed!"); + + cout << "All tests passed successfully!" << endl; + + return 0; +} diff -Nru primesieve-6.3+ds/test/next_prime1.cpp primesieve-7.0+ds/test/next_prime1.cpp --- primesieve-6.3+ds/test/next_prime1.cpp 2017-11-18 12:38:21.000000000 +0000 +++ primesieve-7.0+ds/test/next_prime1.cpp 2018-06-08 08:51:41.000000000 +0000 @@ -57,16 +57,20 @@ cout << "Sum of the primes below 10^9 = " << sum; check(sum == 24739512092254535ull); - uint64_t p1 = primes[primes.size() - 1]; - uint64_t p2 = primes[primes.size() - 2]; - it.skipto(p1); - prime = it.prev_prime(); - cout << "prev_prime(" << p1 << ") = " << prime; - check(prime == p2); - + it.skipto(primes.back() - 200, primes.back()); prime = it.next_prime(); - cout << "next_prime(" << p2 << ") = " << prime; - check(prime == p1); + + while (prime <= primes.back()) + prime = it.next_prime(); + + for (uint64_t i = 1; i < 1000; i++) + { + uint64_t old = prime; + uint64_t p = primes[primes.size() - i]; + prime = it.prev_prime(); + cout << "prev_prime(" << old << ") = " << prime; + check(prime == p); + } cout << endl; cout << "All tests passed successfully!" << endl; diff -Nru primesieve-6.3+ds/test/next_prime2.c primesieve-7.0+ds/test/next_prime2.c --- primesieve-6.3+ds/test/next_prime2.c 2017-11-18 12:38:21.000000000 +0000 +++ primesieve-7.0+ds/test/next_prime2.c 2018-06-08 08:51:41.000000000 +0000 @@ -34,6 +34,7 @@ primesieve_init(&it); uint64_t i; + uint64_t old; uint64_t prime; uint64_t max_prime = primes[size - 1]; uint64_t sum = 0; @@ -60,21 +61,32 @@ printf("Sum of the primes below 10^9 = %" PRIu64, sum); check(sum == 24739512092254535ull); - uint64_t p1 = primes[size - 1]; - uint64_t p2 = primes[size - 2]; - primesieve_skipto(&it, p1, p2); - prime = primesieve_prev_prime(&it); - printf("prev_prime(%" PRIu64 ") = %" PRIu64, p1, prime); - check(prime == p2); - + primesieve_skipto(&it, max_prime / 2, max_prime); prime = primesieve_next_prime(&it); - printf("next_prime(%" PRIu64 ") = %" PRIu64, p2, prime); - check(prime == p1); - primesieve_skipto(&it, 18446744073709551557ull, 0); + while (prime <= max_prime) + prime = primesieve_next_prime(&it); + + for (i = 1; i < 1000; i++) + { + old = prime; + prime = primesieve_prev_prime(&it); + printf("prev_prime(%" PRIu64 ") = %" PRIu64, old, prime); + check(prime == primes[size - i]); + } + + primesieve_skipto(&it, 18446744073709551556ull, 0); prime = primesieve_next_prime(&it); - printf("next_prime(%" PRIu64 ") = %" PRIu64, UINT64_C(18446744073709551557), prime); - check(prime == 18446744073709551615ull); + printf("next_prime(18446744073709551556) = %" PRIu64, prime); + check(prime == 18446744073709551557ull); + + for (i = 0; i < 100; i++) + { + old = prime; + prime = primesieve_next_prime(&it); + printf("next_prime(%" PRIu64 ") = %" PRIu64, old, prime); + check(prime == 18446744073709551615ull); + } primesieve_free(primes); primesieve_free_iterator(&it); diff -Nru primesieve-6.3+ds/test/nth_prime2.cpp primesieve-7.0+ds/test/nth_prime2.cpp --- primesieve-6.3+ds/test/nth_prime2.cpp 2017-11-18 12:38:21.000000000 +0000 +++ primesieve-7.0+ds/test/nth_prime2.cpp 2018-06-08 08:51:41.000000000 +0000 @@ -72,6 +72,7 @@ n = -1; start = 2; res = nth_prime(n, start); + cerr << "ERROR: nth_prime(" << n << ", " << start << ") = " << res; return 1; } catch (primesieve_error& e) @@ -84,6 +85,7 @@ n = 1; start = 18446744073709551557ull; res = nth_prime(n, start); + cerr << "ERROR: nth_prime(" << n << ", " << start << ") = " << res; return 1; } catch (primesieve_error& e) diff -Nru primesieve-6.3+ds/test/nth_prime3.cpp primesieve-7.0+ds/test/nth_prime3.cpp --- primesieve-6.3+ds/test/nth_prime3.cpp 2017-11-18 12:38:21.000000000 +0000 +++ primesieve-7.0+ds/test/nth_prime3.cpp 2018-06-08 08:51:41.000000000 +0000 @@ -37,14 +37,18 @@ int main() { - for (int i = 3; i <= 7; i++) + // Set a small sieve size in order to + // ensure many segments are sieved + set_sieve_size(16); + + for (int i = 3; i <= 6; i++) { - for (int j = 10; j <= 13; j++) + for (int j = 8; j <= 10; j++) { int64_t n = (int64_t) pow(10.0, i); int64_t start = (int64_t) pow(10.0, j); int64_t iters = 5; - + cout << "nth_prime_test(" << n << ", " << start << ", " << iters << ")"; nth_prime_test(n, start, iters); cout << " = OK" << endl; diff -Nru primesieve-6.3+ds/test/number_of_bits.cpp primesieve-7.0+ds/test/number_of_bits.cpp --- primesieve-6.3+ds/test/number_of_bits.cpp 1970-01-01 00:00:00.000000000 +0000 +++ primesieve-7.0+ds/test/number_of_bits.cpp 2018-06-08 08:51:41.000000000 +0000 @@ -0,0 +1,64 @@ +/// +/// @file number_of_bits.cpp +/// @brief Test numberOfBits(x) function. +/// +/// Copyright (C) 2018 Kim Walisch, +/// +/// This file is distributed under the BSD License. See the COPYING +/// file in the top level directory. +/// + +#include + +#include +#include + +using namespace std; +using namespace primesieve; + +void check(bool OK) +{ + cout << " " << (OK ? "OK" : "ERROR") << "\n"; + if (!OK) + exit(1); +} + +int main() +{ + int8_t i8 = 0; + cout << "numberOfBits(int8_t) = " << (int) numberOfBits(i8); + check(numberOfBits(i8) == 8); + + uint8_t ui8 = 0; + cout << "numberOfBits(uint8_t) = " << (int) numberOfBits(ui8); + check(numberOfBits(ui8) == 8); + + int16_t i16 = 0; + cout << "numberOfBits(int16_t) = " << numberOfBits(i16); + check(numberOfBits(i16) == 16); + + uint16_t ui16 = 0; + cout << "numberOfBits(uint16_t) = " << numberOfBits(ui16); + check(numberOfBits(ui16) == 16); + + int32_t i32 = 0; + cout << "numberOfBits(int32_t) = " << numberOfBits(i32); + check(numberOfBits(i32) == 32); + + uint32_t ui32 = 0; + cout << "numberOfBits(uint32_t) = " << numberOfBits(ui32); + check(numberOfBits(ui32) == 32); + + int64_t i64 = 0; + cout << "numberOfBits(int64_t) = " << numberOfBits(i64); + check(numberOfBits(i64) == 64); + + uint64_t ui64 = 0; + cout << "numberOfBits(uint64_t) = " << numberOfBits(ui64); + check(numberOfBits(ui64) == 64); + + cout << endl; + cout << "All tests passed successfully!" << endl; + + return 0; +} diff -Nru primesieve-6.3+ds/test/prev_prime1.cpp primesieve-7.0+ds/test/prev_prime1.cpp --- primesieve-6.3+ds/test/prev_prime1.cpp 2017-11-18 12:38:21.000000000 +0000 +++ primesieve-7.0+ds/test/prev_prime1.cpp 2018-06-08 08:51:41.000000000 +0000 @@ -46,27 +46,51 @@ check(prime == primes[i - 1]); } - it.skipto(1000000000); + it.skipto(100000000); prime = it.prev_prime(); uint64_t sum = 0; - // iterate over the primes below 10^9 + // iterate over the primes below 10^8 for (; prime > 0; prime = it.prev_prime()) sum += prime; - cout << "Sum of the primes below 10^9 = " << sum; - check(sum == 24739512092254535ull); + cout << "Sum of the primes below 10^8 = " << sum; + check(sum == 279209790387276ull); - uint64_t p1 = primes[primes.size() - 1]; - uint64_t p2 = primes[primes.size() - 2]; - it.skipto(p2); - prime = it.next_prime(); - cout << "next_prime(" << p2 << ") = " << prime; - check(prime == p1); + for (uint64_t i = 0; i < 1000; i++) + { + prime = it.prev_prime(); + cout << "prev_prime(0) = " << prime; + check(prime == 0); + } - prime = it.prev_prime(); - cout << "prev_prime(" << p1 << ") = " << prime; - check(prime == p2); + for (uint64_t i = 0; i < 1000; i++) + { + uint64_t old = prime; + prime = it.next_prime(); + cout << "next_prime(" << old << ") = " << prime; + check(prime == primes[i]); + } + + it.skipto(primes.back()); + + for (uint64_t i = 0; i < 1000; i++) + { + prime = it.prev_prime(); + uint64_t p1 = primes.size() - (i + 1); + uint64_t p2 = primes.size() - (i + 2); + cout << "prev_prime(" << primes[p1] << ") = " << prime; + check(prime == primes[p2]); + } + + for (uint64_t i = 0; i < 1000; i++) + { + uint64_t old = prime; + uint64_t j = primes.size() - 1000 + i; + prime = it.next_prime(); + cout << "next_prime(" << old << ") = " << prime; + check(prime == primes[j]); + } it.skipto(18446744073709551615ull, 18446744073709551557ull); prime = it.prev_prime(); diff -Nru primesieve-6.3+ds/test/prev_prime2.c primesieve-7.0+ds/test/prev_prime2.c --- primesieve-6.3+ds/test/prev_prime2.c 2017-11-18 12:38:21.000000000 +0000 +++ primesieve-7.0+ds/test/prev_prime2.c 2018-06-08 08:51:41.000000000 +0000 @@ -2,7 +2,7 @@ /// @file prev_prime2.cpp /// @brief Test primesieve_prev_prime(). /// -/// Copyright (C) 2017 Kim Walisch, +/// Copyright (C) 2018 Kim Walisch, /// /// This file is distributed under the BSD License. See the COPYING /// file in the top level directory. @@ -36,6 +36,7 @@ uint64_t i; uint64_t prime; uint64_t sum = 0; + uint64_t old, p1, p2; for (i = size - 1; i > 0; i--) { @@ -50,25 +51,49 @@ check(prime == primes[i - 1]); } - primesieve_skipto(&it, 1000000000, 0); + primesieve_skipto(&it, 100000000, 0); - // iterate over the primes below 10^9 + // iterate over the primes below 10^8 while ((prime = primesieve_prev_prime(&it)) > 0) sum += prime; - printf("Sum of the primes below 10^9 = %" PRIu64, sum); - check(sum == 24739512092254535ull); + printf("Sum of the primes below 10^8 = %" PRIu64, sum); + check(sum == 279209790387276ull); - uint64_t p1 = primes[size - 1]; - uint64_t p2 = primes[size - 2]; - primesieve_skipto(&it, p2, p1); - prime = primesieve_next_prime(&it); - printf("next_prime(%" PRIu64 ") = %" PRIu64, p2, prime); - check(prime == p1); - - prime = primesieve_prev_prime(&it); - printf("prev_prime(%" PRIu64 ") = %" PRIu64, p1, prime); - check(prime == p2); + for (i = 0; i < 1000; i++) + { + prime = primesieve_prev_prime(&it); + printf("prev_prime(0) = %" PRIu64, prime); + check(prime == 0); + } + + for (i = 0; i < 1000; i++) + { + old = prime; + prime = primesieve_next_prime(&it); + printf("next_prime(%" PRIu64 ") = %" PRIu64, old, prime); + check(prime == primes[i]); + } + + primesieve_skipto(&it, primes[size - 1], 0); + + for (i = 0; i < 1000; i++) + { + p1 = primes[size - (i + 1)]; + p2 = primes[size - (i + 2)]; + prime = primesieve_prev_prime(&it); + printf("prev_prime(%" PRIu64 ") = %" PRIu64, p1, prime); + check(prime == p2); + } + + for (i = 0; i < 1000; i++) + { + old = prime; + p1 = size - 1000 + i; + prime = primesieve_next_prime(&it); + printf("next_prime(%" PRIu64 ") = %" PRIu64, old, prime); + check(prime == primes[p1]); + } primesieve_free(primes); primesieve_free_iterator(&it);