Thanks for using Compiler Explorer
Sponsors
Jakt
C++
Ada
Algol68
Analysis
Android Java
Android Kotlin
Assembly
C
C3
Carbon
C with Coccinelle
C++ with Coccinelle
C++ (Circle)
CIRCT
Clean
Clojure
CMake
CMakeScript
COBOL
C++ for OpenCL
MLIR
Cppx
Cppx-Blue
Cppx-Gold
Cpp2-cppfront
Crystal
C#
CUDA C++
D
Dart
Elixir
Erlang
Fortran
F#
GLSL
Go
Haskell
HLSL
Hook
Hylo
IL
ispc
Java
Julia
Kotlin
LLVM IR
LLVM MIR
Modula-2
Mojo
Nim
Numba
Nix
Objective-C
Objective-C++
OCaml
Odin
OpenCL C
Pascal
Pony
PTX
Python
Racket
Raku
Ruby
Rust
Sail
Snowball
Scala
Slang
Solidity
Spice
SPIR-V
Swift
LLVM TableGen
Toit
Triton
TypeScript Native
V
Vala
Visual Basic
Vyper
WASM
Yul (Solidity IR)
Zig
Javascript
GIMPLE
Ygen
sway
c++ source #1
Output
Compile to binary object
Link to binary
Execute the code
Intel asm syntax
Demangle identifiers
Verbose demangling
Filters
Unused labels
Library functions
Directives
Comments
Horizontal whitespace
Debug intrinsics
Compiler
6502-c++ 11.1.0
ARM GCC 10.2.0
ARM GCC 10.3.0
ARM GCC 10.4.0
ARM GCC 10.5.0
ARM GCC 11.1.0
ARM GCC 11.2.0
ARM GCC 11.3.0
ARM GCC 11.4.0
ARM GCC 12.1.0
ARM GCC 12.2.0
ARM GCC 12.3.0
ARM GCC 12.4.0
ARM GCC 12.5.0
ARM GCC 13.1.0
ARM GCC 13.2.0
ARM GCC 13.2.0 (unknown-eabi)
ARM GCC 13.3.0
ARM GCC 13.3.0 (unknown-eabi)
ARM GCC 13.4.0
ARM GCC 13.4.0 (unknown-eabi)
ARM GCC 14.1.0
ARM GCC 14.1.0 (unknown-eabi)
ARM GCC 14.2.0
ARM GCC 14.2.0 (unknown-eabi)
ARM GCC 14.3.0
ARM GCC 14.3.0 (unknown-eabi)
ARM GCC 15.1.0
ARM GCC 15.1.0 (unknown-eabi)
ARM GCC 15.2.0
ARM GCC 15.2.0 (unknown-eabi)
ARM GCC 4.5.4
ARM GCC 4.6.4
ARM GCC 5.4
ARM GCC 6.3.0
ARM GCC 6.4.0
ARM GCC 7.3.0
ARM GCC 7.5.0
ARM GCC 8.2.0
ARM GCC 8.5.0
ARM GCC 9.3.0
ARM GCC 9.4.0
ARM GCC 9.5.0
ARM GCC trunk
ARM gcc 10.2.1 (none)
ARM gcc 10.3.1 (2021.07 none)
ARM gcc 10.3.1 (2021.10 none)
ARM gcc 11.2.1 (none)
ARM gcc 5.4.1 (none)
ARM gcc 7.2.1 (none)
ARM gcc 8.2 (WinCE)
ARM gcc 8.3.1 (none)
ARM gcc 9.2.1 (none)
ARM msvc v19.0 (ex-WINE)
ARM msvc v19.10 (ex-WINE)
ARM msvc v19.14 (ex-WINE)
ARM64 Morello gcc 10.1 Alpha 2
ARM64 gcc 10.2
ARM64 gcc 10.3
ARM64 gcc 10.4
ARM64 gcc 10.5.0
ARM64 gcc 11.1
ARM64 gcc 11.2
ARM64 gcc 11.3
ARM64 gcc 11.4.0
ARM64 gcc 12.1
ARM64 gcc 12.2.0
ARM64 gcc 12.3.0
ARM64 gcc 12.4.0
ARM64 gcc 12.5.0
ARM64 gcc 13.1.0
ARM64 gcc 13.2.0
ARM64 gcc 13.3.0
ARM64 gcc 13.4.0
ARM64 gcc 14.1.0
ARM64 gcc 14.2.0
ARM64 gcc 14.3.0
ARM64 gcc 15.1.0
ARM64 gcc 15.2.0
ARM64 gcc 4.9.4
ARM64 gcc 5.4
ARM64 gcc 5.5.0
ARM64 gcc 6.3
ARM64 gcc 6.4
ARM64 gcc 7.3
ARM64 gcc 7.5
ARM64 gcc 8.2
ARM64 gcc 8.5
ARM64 gcc 9.3
ARM64 gcc 9.4
ARM64 gcc 9.5
ARM64 gcc trunk
ARM64 msvc v19.14 (ex-WINE)
AVR gcc 10.3.0
AVR gcc 11.1.0
AVR gcc 12.1.0
AVR gcc 12.2.0
AVR gcc 12.3.0
AVR gcc 12.4.0
AVR gcc 12.5.0
AVR gcc 13.1.0
AVR gcc 13.2.0
AVR gcc 13.3.0
AVR gcc 13.4.0
AVR gcc 14.1.0
AVR gcc 14.2.0
AVR gcc 14.3.0
AVR gcc 15.1.0
AVR gcc 15.2.0
AVR gcc 4.5.4
AVR gcc 4.6.4
AVR gcc 5.4.0
AVR gcc 9.2.0
AVR gcc 9.3.0
Arduino Mega (1.8.9)
Arduino Uno (1.8.9)
BPF clang (trunk)
BPF clang 13.0.0
BPF clang 14.0.0
BPF clang 15.0.0
BPF clang 16.0.0
BPF clang 17.0.1
BPF clang 18.1.0
BPF clang 19.1.0
BPF clang 20.1.0
BPF clang 21.1.0
EDG (experimental reflection)
EDG 6.5
EDG 6.5 (GNU mode gcc 13)
EDG 6.6
EDG 6.6 (GNU mode gcc 13)
EDG 6.7
EDG 6.7 (GNU mode gcc 14)
FRC 2019
FRC 2020
FRC 2023
HPPA gcc 14.2.0
HPPA gcc 14.3.0
HPPA gcc 15.1.0
HPPA gcc 15.2.0
KVX ACB 4.1.0 (GCC 7.5.0)
KVX ACB 4.1.0-cd1 (GCC 7.5.0)
KVX ACB 4.10.0 (GCC 10.3.1)
KVX ACB 4.11.1 (GCC 10.3.1)
KVX ACB 4.12.0 (GCC 11.3.0)
KVX ACB 4.2.0 (GCC 7.5.0)
KVX ACB 4.3.0 (GCC 7.5.0)
KVX ACB 4.4.0 (GCC 7.5.0)
KVX ACB 4.6.0 (GCC 9.4.1)
KVX ACB 4.8.0 (GCC 9.4.1)
KVX ACB 4.9.0 (GCC 9.4.1)
KVX ACB 5.0.0 (GCC 12.2.1)
KVX ACB 5.2.0 (GCC 13.2.1)
LoongArch64 clang (trunk)
LoongArch64 clang 17.0.1
LoongArch64 clang 18.1.0
LoongArch64 clang 19.1.0
LoongArch64 clang 20.1.0
LoongArch64 clang 21.1.0
M68K gcc 13.1.0
M68K gcc 13.2.0
M68K gcc 13.3.0
M68K gcc 13.4.0
M68K gcc 14.1.0
M68K gcc 14.2.0
M68K gcc 14.3.0
M68K gcc 15.1.0
M68K gcc 15.2.0
M68k clang (trunk)
MRISC32 gcc (trunk)
MSP430 gcc 4.5.3
MSP430 gcc 5.3.0
MSP430 gcc 6.2.1
MinGW clang 14.0.3
MinGW clang 14.0.6
MinGW clang 15.0.7
MinGW clang 16.0.0
MinGW clang 16.0.2
MinGW gcc 11.3.0
MinGW gcc 12.1.0
MinGW gcc 12.2.0
MinGW gcc 13.1.0
MinGW gcc 14.3.0
MinGW gcc 15.2.0
RISC-V (32-bits) gcc (trunk)
RISC-V (32-bits) gcc 10.2.0
RISC-V (32-bits) gcc 10.3.0
RISC-V (32-bits) gcc 11.2.0
RISC-V (32-bits) gcc 11.3.0
RISC-V (32-bits) gcc 11.4.0
RISC-V (32-bits) gcc 12.1.0
RISC-V (32-bits) gcc 12.2.0
RISC-V (32-bits) gcc 12.3.0
RISC-V (32-bits) gcc 12.4.0
RISC-V (32-bits) gcc 12.5.0
RISC-V (32-bits) gcc 13.1.0
RISC-V (32-bits) gcc 13.2.0
RISC-V (32-bits) gcc 13.3.0
RISC-V (32-bits) gcc 13.4.0
RISC-V (32-bits) gcc 14.1.0
RISC-V (32-bits) gcc 14.2.0
RISC-V (32-bits) gcc 14.3.0
RISC-V (32-bits) gcc 15.1.0
RISC-V (32-bits) gcc 15.2.0
RISC-V (32-bits) gcc 8.2.0
RISC-V (32-bits) gcc 8.5.0
RISC-V (32-bits) gcc 9.4.0
RISC-V (64-bits) gcc (trunk)
RISC-V (64-bits) gcc 10.2.0
RISC-V (64-bits) gcc 10.3.0
RISC-V (64-bits) gcc 11.2.0
RISC-V (64-bits) gcc 11.3.0
RISC-V (64-bits) gcc 11.4.0
RISC-V (64-bits) gcc 12.1.0
RISC-V (64-bits) gcc 12.2.0
RISC-V (64-bits) gcc 12.3.0
RISC-V (64-bits) gcc 12.4.0
RISC-V (64-bits) gcc 12.5.0
RISC-V (64-bits) gcc 13.1.0
RISC-V (64-bits) gcc 13.2.0
RISC-V (64-bits) gcc 13.3.0
RISC-V (64-bits) gcc 13.4.0
RISC-V (64-bits) gcc 14.1.0
RISC-V (64-bits) gcc 14.2.0
RISC-V (64-bits) gcc 14.3.0
RISC-V (64-bits) gcc 15.1.0
RISC-V (64-bits) gcc 15.2.0
RISC-V (64-bits) gcc 8.2.0
RISC-V (64-bits) gcc 8.5.0
RISC-V (64-bits) gcc 9.4.0
RISC-V rv32gc clang (trunk)
RISC-V rv32gc clang 10.0.0
RISC-V rv32gc clang 10.0.1
RISC-V rv32gc clang 11.0.0
RISC-V rv32gc clang 11.0.1
RISC-V rv32gc clang 12.0.0
RISC-V rv32gc clang 12.0.1
RISC-V rv32gc clang 13.0.0
RISC-V rv32gc clang 13.0.1
RISC-V rv32gc clang 14.0.0
RISC-V rv32gc clang 15.0.0
RISC-V rv32gc clang 16.0.0
RISC-V rv32gc clang 17.0.1
RISC-V rv32gc clang 18.1.0
RISC-V rv32gc clang 19.1.0
RISC-V rv32gc clang 20.1.0
RISC-V rv32gc clang 21.1.0
RISC-V rv32gc clang 9.0.0
RISC-V rv32gc clang 9.0.1
RISC-V rv64gc clang (trunk)
RISC-V rv64gc clang 10.0.0
RISC-V rv64gc clang 10.0.1
RISC-V rv64gc clang 11.0.0
RISC-V rv64gc clang 11.0.1
RISC-V rv64gc clang 12.0.0
RISC-V rv64gc clang 12.0.1
RISC-V rv64gc clang 13.0.0
RISC-V rv64gc clang 13.0.1
RISC-V rv64gc clang 14.0.0
RISC-V rv64gc clang 15.0.0
RISC-V rv64gc clang 16.0.0
RISC-V rv64gc clang 17.0.1
RISC-V rv64gc clang 18.1.0
RISC-V rv64gc clang 19.1.0
RISC-V rv64gc clang 20.1.0
RISC-V rv64gc clang 21.1.0
RISC-V rv64gc clang 9.0.0
RISC-V rv64gc clang 9.0.1
Raspbian Buster
Raspbian Stretch
SPARC LEON gcc 12.2.0
SPARC LEON gcc 12.3.0
SPARC LEON gcc 12.4.0
SPARC LEON gcc 12.5.0
SPARC LEON gcc 13.1.0
SPARC LEON gcc 13.2.0
SPARC LEON gcc 13.3.0
SPARC LEON gcc 13.4.0
SPARC LEON gcc 14.1.0
SPARC LEON gcc 14.2.0
SPARC LEON gcc 14.3.0
SPARC LEON gcc 15.1.0
SPARC LEON gcc 15.2.0
SPARC gcc 12.2.0
SPARC gcc 12.3.0
SPARC gcc 12.4.0
SPARC gcc 12.5.0
SPARC gcc 13.1.0
SPARC gcc 13.2.0
SPARC gcc 13.3.0
SPARC gcc 13.4.0
SPARC gcc 14.1.0
SPARC gcc 14.2.0
SPARC gcc 14.3.0
SPARC gcc 15.1.0
SPARC gcc 15.2.0
SPARC64 gcc 12.2.0
SPARC64 gcc 12.3.0
SPARC64 gcc 12.4.0
SPARC64 gcc 12.5.0
SPARC64 gcc 13.1.0
SPARC64 gcc 13.2.0
SPARC64 gcc 13.3.0
SPARC64 gcc 13.4.0
SPARC64 gcc 14.1.0
SPARC64 gcc 14.2.0
SPARC64 gcc 14.3.0
SPARC64 gcc 15.1.0
SPARC64 gcc 15.2.0
TI C6x gcc 12.2.0
TI C6x gcc 12.3.0
TI C6x gcc 12.4.0
TI C6x gcc 12.5.0
TI C6x gcc 13.1.0
TI C6x gcc 13.2.0
TI C6x gcc 13.3.0
TI C6x gcc 13.4.0
TI C6x gcc 14.1.0
TI C6x gcc 14.2.0
TI C6x gcc 14.3.0
TI C6x gcc 15.1.0
TI C6x gcc 15.2.0
TI CL430 21.6.1
Tricore gcc 11.3.0 (EEESlab)
VAX gcc NetBSDELF 10.4.0
VAX gcc NetBSDELF 10.5.0 (Nov 15 03:50:22 2023)
VAX gcc NetBSDELF 12.4.0 (Apr 16 05:27 2025)
WebAssembly clang (trunk)
Xtensa ESP32 gcc 11.2.0 (2022r1)
Xtensa ESP32 gcc 12.2.0 (20230208)
Xtensa ESP32 gcc 14.2.0 (20241119)
Xtensa ESP32 gcc 8.2.0 (2019r2)
Xtensa ESP32 gcc 8.2.0 (2020r1)
Xtensa ESP32 gcc 8.2.0 (2020r2)
Xtensa ESP32 gcc 8.4.0 (2020r3)
Xtensa ESP32 gcc 8.4.0 (2021r1)
Xtensa ESP32 gcc 8.4.0 (2021r2)
Xtensa ESP32-S2 gcc 11.2.0 (2022r1)
Xtensa ESP32-S2 gcc 12.2.0 (20230208)
Xtensa ESP32-S2 gcc 14.2.0 (20241119)
Xtensa ESP32-S2 gcc 8.2.0 (2019r2)
Xtensa ESP32-S2 gcc 8.2.0 (2020r1)
Xtensa ESP32-S2 gcc 8.2.0 (2020r2)
Xtensa ESP32-S2 gcc 8.4.0 (2020r3)
Xtensa ESP32-S2 gcc 8.4.0 (2021r1)
Xtensa ESP32-S2 gcc 8.4.0 (2021r2)
Xtensa ESP32-S3 gcc 11.2.0 (2022r1)
Xtensa ESP32-S3 gcc 12.2.0 (20230208)
Xtensa ESP32-S3 gcc 14.2.0 (20241119)
Xtensa ESP32-S3 gcc 8.4.0 (2020r3)
Xtensa ESP32-S3 gcc 8.4.0 (2021r1)
Xtensa ESP32-S3 gcc 8.4.0 (2021r2)
arm64 msvc v19.20 VS16.0
arm64 msvc v19.21 VS16.1
arm64 msvc v19.22 VS16.2
arm64 msvc v19.23 VS16.3
arm64 msvc v19.24 VS16.4
arm64 msvc v19.25 VS16.5
arm64 msvc v19.27 VS16.7
arm64 msvc v19.28 VS16.8
arm64 msvc v19.28 VS16.9
arm64 msvc v19.29 VS16.10
arm64 msvc v19.29 VS16.11
arm64 msvc v19.30 VS17.0
arm64 msvc v19.31 VS17.1
arm64 msvc v19.32 VS17.2
arm64 msvc v19.33 VS17.3
arm64 msvc v19.34 VS17.4
arm64 msvc v19.35 VS17.5
arm64 msvc v19.36 VS17.6
arm64 msvc v19.37 VS17.7
arm64 msvc v19.38 VS17.8
arm64 msvc v19.39 VS17.9
arm64 msvc v19.40 VS17.10
arm64 msvc v19.41 VS17.11
arm64 msvc v19.42 VS17.12
arm64 msvc v19.43 VS17.13
arm64 msvc v19.latest
armv7-a clang (trunk)
armv7-a clang 10.0.0
armv7-a clang 10.0.1
armv7-a clang 11.0.0
armv7-a clang 11.0.1
armv7-a clang 12.0.0
armv7-a clang 12.0.1
armv7-a clang 13.0.0
armv7-a clang 13.0.1
armv7-a clang 14.0.0
armv7-a clang 15.0.0
armv7-a clang 16.0.0
armv7-a clang 17.0.1
armv7-a clang 18.1.0
armv7-a clang 19.1.0
armv7-a clang 20.1.0
armv7-a clang 21.1.0
armv7-a clang 9.0.0
armv7-a clang 9.0.1
armv8-a clang (all architectural features, trunk)
armv8-a clang (trunk)
armv8-a clang 10.0.0
armv8-a clang 10.0.1
armv8-a clang 11.0.0
armv8-a clang 11.0.1
armv8-a clang 12.0.0
armv8-a clang 13.0.0
armv8-a clang 14.0.0
armv8-a clang 15.0.0
armv8-a clang 16.0.0
armv8-a clang 17.0.1
armv8-a clang 18.1.0
armv8-a clang 19.1.0
armv8-a clang 20.1.0
armv8-a clang 21.1.0
armv8-a clang 9.0.0
armv8-a clang 9.0.1
clad trunk (clang 21.1.0)
clad v1.10 (clang 20.1.0)
clad v1.8 (clang 18.1.0)
clad v1.9 (clang 19.1.0)
clad v2.00 (clang 20.1.0)
clad v2.1 (clang 21.1.0)
clang-cl 18.1.0
ellcc 0.1.33
ellcc 0.1.34
ellcc 2017-07-16
ez80-clang 15.0.0
ez80-clang 15.0.7
hexagon-clang 16.0.5
llvm-mos atari2600-3e
llvm-mos atari2600-4k
llvm-mos atari2600-common
llvm-mos atari5200-supercart
llvm-mos atari8-cart-megacart
llvm-mos atari8-cart-std
llvm-mos atari8-cart-xegs
llvm-mos atari8-common
llvm-mos atari8-dos
llvm-mos c128
llvm-mos c64
llvm-mos commodore
llvm-mos cpm65
llvm-mos cx16
llvm-mos dodo
llvm-mos eater
llvm-mos mega65
llvm-mos nes
llvm-mos nes-action53
llvm-mos nes-cnrom
llvm-mos nes-gtrom
llvm-mos nes-mmc1
llvm-mos nes-mmc3
llvm-mos nes-nrom
llvm-mos nes-unrom
llvm-mos nes-unrom-512
llvm-mos osi-c1p
llvm-mos pce
llvm-mos pce-cd
llvm-mos pce-common
llvm-mos pet
llvm-mos rp6502
llvm-mos rpc8e
llvm-mos supervision
llvm-mos vic20
loongarch64 gcc 12.2.0
loongarch64 gcc 12.3.0
loongarch64 gcc 12.4.0
loongarch64 gcc 12.5.0
loongarch64 gcc 13.1.0
loongarch64 gcc 13.2.0
loongarch64 gcc 13.3.0
loongarch64 gcc 13.4.0
loongarch64 gcc 14.1.0
loongarch64 gcc 14.2.0
loongarch64 gcc 14.3.0
loongarch64 gcc 15.1.0
loongarch64 gcc 15.2.0
mips clang 13.0.0
mips clang 14.0.0
mips clang 15.0.0
mips clang 16.0.0
mips clang 17.0.1
mips clang 18.1.0
mips clang 19.1.0
mips clang 20.1.0
mips clang 21.1.0
mips gcc 11.2.0
mips gcc 12.1.0
mips gcc 12.2.0
mips gcc 12.3.0
mips gcc 12.4.0
mips gcc 12.5.0
mips gcc 13.1.0
mips gcc 13.2.0
mips gcc 13.3.0
mips gcc 13.4.0
mips gcc 14.1.0
mips gcc 14.2.0
mips gcc 14.3.0
mips gcc 15.1.0
mips gcc 15.2.0
mips gcc 4.9.4
mips gcc 5.4
mips gcc 5.5.0
mips gcc 9.3.0 (codescape)
mips gcc 9.5.0
mips64 (el) gcc 12.1.0
mips64 (el) gcc 12.2.0
mips64 (el) gcc 12.3.0
mips64 (el) gcc 12.4.0
mips64 (el) gcc 12.5.0
mips64 (el) gcc 13.1.0
mips64 (el) gcc 13.2.0
mips64 (el) gcc 13.3.0
mips64 (el) gcc 13.4.0
mips64 (el) gcc 14.1.0
mips64 (el) gcc 14.2.0
mips64 (el) gcc 14.3.0
mips64 (el) gcc 15.1.0
mips64 (el) gcc 15.2.0
mips64 (el) gcc 4.9.4
mips64 (el) gcc 5.4.0
mips64 (el) gcc 5.5.0
mips64 (el) gcc 9.5.0
mips64 clang 13.0.0
mips64 clang 14.0.0
mips64 clang 15.0.0
mips64 clang 16.0.0
mips64 clang 17.0.1
mips64 clang 18.1.0
mips64 clang 19.1.0
mips64 clang 20.1.0
mips64 clang 21.1.0
mips64 gcc 11.2.0
mips64 gcc 12.1.0
mips64 gcc 12.2.0
mips64 gcc 12.3.0
mips64 gcc 12.4.0
mips64 gcc 12.5.0
mips64 gcc 13.1.0
mips64 gcc 13.2.0
mips64 gcc 13.3.0
mips64 gcc 13.4.0
mips64 gcc 14.1.0
mips64 gcc 14.2.0
mips64 gcc 14.3.0
mips64 gcc 15.1.0
mips64 gcc 15.2.0
mips64 gcc 4.9.4
mips64 gcc 5.4.0
mips64 gcc 5.5.0
mips64 gcc 9.5.0
mips64el clang 13.0.0
mips64el clang 14.0.0
mips64el clang 15.0.0
mips64el clang 16.0.0
mips64el clang 17.0.1
mips64el clang 18.1.0
mips64el clang 19.1.0
mips64el clang 20.1.0
mips64el clang 21.1.0
mipsel clang 13.0.0
mipsel clang 14.0.0
mipsel clang 15.0.0
mipsel clang 16.0.0
mipsel clang 17.0.1
mipsel clang 18.1.0
mipsel clang 19.1.0
mipsel clang 20.1.0
mipsel clang 21.1.0
mipsel gcc 12.1.0
mipsel gcc 12.2.0
mipsel gcc 12.3.0
mipsel gcc 12.4.0
mipsel gcc 12.5.0
mipsel gcc 13.1.0
mipsel gcc 13.2.0
mipsel gcc 13.3.0
mipsel gcc 13.4.0
mipsel gcc 14.1.0
mipsel gcc 14.2.0
mipsel gcc 14.3.0
mipsel gcc 15.1.0
mipsel gcc 15.2.0
mipsel gcc 4.9.4
mipsel gcc 5.4.0
mipsel gcc 5.5.0
mipsel gcc 9.5.0
nanoMIPS gcc 6.3.0 (mtk)
power gcc 11.2.0
power gcc 12.1.0
power gcc 12.2.0
power gcc 12.3.0
power gcc 12.4.0
power gcc 12.5.0
power gcc 13.1.0
power gcc 13.2.0
power gcc 13.3.0
power gcc 13.4.0
power gcc 14.1.0
power gcc 14.2.0
power gcc 14.3.0
power gcc 15.1.0
power gcc 15.2.0
power gcc 4.8.5
power64 AT12.0 (gcc8)
power64 AT13.0 (gcc9)
power64 gcc 11.2.0
power64 gcc 12.1.0
power64 gcc 12.2.0
power64 gcc 12.3.0
power64 gcc 12.4.0
power64 gcc 12.5.0
power64 gcc 13.1.0
power64 gcc 13.2.0
power64 gcc 13.3.0
power64 gcc 13.4.0
power64 gcc 14.1.0
power64 gcc 14.2.0
power64 gcc 14.3.0
power64 gcc 15.1.0
power64 gcc 15.2.0
power64 gcc trunk
power64le AT12.0 (gcc8)
power64le AT13.0 (gcc9)
power64le clang (trunk)
power64le gcc 11.2.0
power64le gcc 12.1.0
power64le gcc 12.2.0
power64le gcc 12.3.0
power64le gcc 12.4.0
power64le gcc 12.5.0
power64le gcc 13.1.0
power64le gcc 13.2.0
power64le gcc 13.3.0
power64le gcc 13.4.0
power64le gcc 14.1.0
power64le gcc 14.2.0
power64le gcc 14.3.0
power64le gcc 15.1.0
power64le gcc 15.2.0
power64le gcc 6.3.0
power64le gcc trunk
powerpc64 clang (trunk)
qnx 8.0.0
s390x gcc 11.2.0
s390x gcc 12.1.0
s390x gcc 12.2.0
s390x gcc 12.3.0
s390x gcc 12.4.0
s390x gcc 12.5.0
s390x gcc 13.1.0
s390x gcc 13.2.0
s390x gcc 13.3.0
s390x gcc 13.4.0
s390x gcc 14.1.0
s390x gcc 14.2.0
s390x gcc 14.3.0
s390x gcc 15.1.0
s390x gcc 15.2.0
sh gcc 12.2.0
sh gcc 12.3.0
sh gcc 12.4.0
sh gcc 12.5.0
sh gcc 13.1.0
sh gcc 13.2.0
sh gcc 13.3.0
sh gcc 13.4.0
sh gcc 14.1.0
sh gcc 14.2.0
sh gcc 14.3.0
sh gcc 15.1.0
sh gcc 15.2.0
sh gcc 4.9.4
sh gcc 9.5.0
vast (trunk)
x64 msvc v19.0 (ex-WINE)
x64 msvc v19.10 (ex-WINE)
x64 msvc v19.14 (ex-WINE)
x64 msvc v19.20 VS16.0
x64 msvc v19.21 VS16.1
x64 msvc v19.22 VS16.2
x64 msvc v19.23 VS16.3
x64 msvc v19.24 VS16.4
x64 msvc v19.25 VS16.5
x64 msvc v19.27 VS16.7
x64 msvc v19.28 VS16.8
x64 msvc v19.28 VS16.9
x64 msvc v19.29 VS16.10
x64 msvc v19.29 VS16.11
x64 msvc v19.30 VS17.0
x64 msvc v19.31 VS17.1
x64 msvc v19.32 VS17.2
x64 msvc v19.33 VS17.3
x64 msvc v19.34 VS17.4
x64 msvc v19.35 VS17.5
x64 msvc v19.36 VS17.6
x64 msvc v19.37 VS17.7
x64 msvc v19.38 VS17.8
x64 msvc v19.39 VS17.9
x64 msvc v19.40 VS17.10
x64 msvc v19.41 VS17.11
x64 msvc v19.42 VS17.12
x64 msvc v19.43 VS17.13
x64 msvc v19.latest
x86 djgpp 4.9.4
x86 djgpp 5.5.0
x86 djgpp 6.4.0
x86 djgpp 7.2.0
x86 msvc v19.0 (ex-WINE)
x86 msvc v19.10 (ex-WINE)
x86 msvc v19.14 (ex-WINE)
x86 msvc v19.20 VS16.0
x86 msvc v19.21 VS16.1
x86 msvc v19.22 VS16.2
x86 msvc v19.23 VS16.3
x86 msvc v19.24 VS16.4
x86 msvc v19.25 VS16.5
x86 msvc v19.27 VS16.7
x86 msvc v19.28 VS16.8
x86 msvc v19.28 VS16.9
x86 msvc v19.29 VS16.10
x86 msvc v19.29 VS16.11
x86 msvc v19.30 VS17.0
x86 msvc v19.31 VS17.1
x86 msvc v19.32 VS17.2
x86 msvc v19.33 VS17.3
x86 msvc v19.34 VS17.4
x86 msvc v19.35 VS17.5
x86 msvc v19.36 VS17.6
x86 msvc v19.37 VS17.7
x86 msvc v19.38 VS17.8
x86 msvc v19.39 VS17.9
x86 msvc v19.40 VS17.10
x86 msvc v19.41 VS17.11
x86 msvc v19.42 VS17.12
x86 msvc v19.43 VS17.13
x86 msvc v19.latest
x86 nvc++ 22.11
x86 nvc++ 22.7
x86 nvc++ 22.9
x86 nvc++ 23.1
x86 nvc++ 23.11
x86 nvc++ 23.3
x86 nvc++ 23.5
x86 nvc++ 23.7
x86 nvc++ 23.9
x86 nvc++ 24.1
x86 nvc++ 24.11
x86 nvc++ 24.3
x86 nvc++ 24.5
x86 nvc++ 24.7
x86 nvc++ 24.9
x86 nvc++ 25.1
x86 nvc++ 25.3
x86 nvc++ 25.5
x86 nvc++ 25.7
x86 nvc++ 25.9
x86-64 Zapcc 190308
x86-64 clang (-fimplicit-constexpr)
x86-64 clang (Chris Bazley N3089)
x86-64 clang (EricWF contracts)
x86-64 clang (amd-staging)
x86-64 clang (assertions trunk)
x86-64 clang (clangir)
x86-64 clang (experimental -Wlifetime)
x86-64 clang (experimental P1061)
x86-64 clang (experimental P1144)
x86-64 clang (experimental P1221)
x86-64 clang (experimental P2998)
x86-64 clang (experimental P3068)
x86-64 clang (experimental P3309)
x86-64 clang (experimental P3367)
x86-64 clang (experimental P3372)
x86-64 clang (experimental P3385)
x86-64 clang (experimental P3776)
x86-64 clang (experimental metaprogramming - P2632)
x86-64 clang (old concepts branch)
x86-64 clang (p1974)
x86-64 clang (pattern matching - P2688)
x86-64 clang (reflection - C++26)
x86-64 clang (reflection - TS)
x86-64 clang (resugar)
x86-64 clang (string interpolation - P3412)
x86-64 clang (thephd.dev)
x86-64 clang (trunk)
x86-64 clang (variadic friends - P2893)
x86-64 clang (widberg)
x86-64 clang 10.0.0
x86-64 clang 10.0.0 (assertions)
x86-64 clang 10.0.1
x86-64 clang 11.0.0
x86-64 clang 11.0.0 (assertions)
x86-64 clang 11.0.1
x86-64 clang 12.0.0
x86-64 clang 12.0.0 (assertions)
x86-64 clang 12.0.1
x86-64 clang 13.0.0
x86-64 clang 13.0.0 (assertions)
x86-64 clang 13.0.1
x86-64 clang 14.0.0
x86-64 clang 14.0.0 (assertions)
x86-64 clang 15.0.0
x86-64 clang 15.0.0 (assertions)
x86-64 clang 16.0.0
x86-64 clang 16.0.0 (assertions)
x86-64 clang 17.0.1
x86-64 clang 17.0.1 (assertions)
x86-64 clang 18.1.0
x86-64 clang 18.1.0 (assertions)
x86-64 clang 19.1.0
x86-64 clang 19.1.0 (assertions)
x86-64 clang 2.6.0 (assertions)
x86-64 clang 2.7.0 (assertions)
x86-64 clang 2.8.0 (assertions)
x86-64 clang 2.9.0 (assertions)
x86-64 clang 20.1.0
x86-64 clang 20.1.0 (assertions)
x86-64 clang 21.1.0
x86-64 clang 21.1.0 (assertions)
x86-64 clang 3.0.0
x86-64 clang 3.0.0 (assertions)
x86-64 clang 3.1
x86-64 clang 3.1 (assertions)
x86-64 clang 3.2
x86-64 clang 3.2 (assertions)
x86-64 clang 3.3
x86-64 clang 3.3 (assertions)
x86-64 clang 3.4 (assertions)
x86-64 clang 3.4.1
x86-64 clang 3.5
x86-64 clang 3.5 (assertions)
x86-64 clang 3.5.1
x86-64 clang 3.5.2
x86-64 clang 3.6
x86-64 clang 3.6 (assertions)
x86-64 clang 3.7
x86-64 clang 3.7 (assertions)
x86-64 clang 3.7.1
x86-64 clang 3.8
x86-64 clang 3.8 (assertions)
x86-64 clang 3.8.1
x86-64 clang 3.9.0
x86-64 clang 3.9.0 (assertions)
x86-64 clang 3.9.1
x86-64 clang 4.0.0
x86-64 clang 4.0.0 (assertions)
x86-64 clang 4.0.1
x86-64 clang 5.0.0
x86-64 clang 5.0.0 (assertions)
x86-64 clang 5.0.1
x86-64 clang 5.0.2
x86-64 clang 6.0.0
x86-64 clang 6.0.0 (assertions)
x86-64 clang 6.0.1
x86-64 clang 7.0.0
x86-64 clang 7.0.0 (assertions)
x86-64 clang 7.0.1
x86-64 clang 7.1.0
x86-64 clang 8.0.0
x86-64 clang 8.0.0 (assertions)
x86-64 clang 8.0.1
x86-64 clang 9.0.0
x86-64 clang 9.0.0 (assertions)
x86-64 clang 9.0.1
x86-64 clang rocm-4.5.2
x86-64 clang rocm-5.0.2
x86-64 clang rocm-5.1.3
x86-64 clang rocm-5.2.3
x86-64 clang rocm-5.3.3
x86-64 clang rocm-5.7.0
x86-64 clang rocm-6.0.2
x86-64 clang rocm-6.1.2
x86-64 clang rocm-6.2.4
x86-64 clang rocm-6.3.3
x86-64 clang rocm-6.4.0
x86-64 clang rocm-7.0.1
x86-64 gcc (P2034 lambdas)
x86-64 gcc (contract labels)
x86-64 gcc (contracts natural syntax)
x86-64 gcc (contracts)
x86-64 gcc (coroutines)
x86-64 gcc (modules)
x86-64 gcc (trunk)
x86-64 gcc 10.1
x86-64 gcc 10.2
x86-64 gcc 10.3
x86-64 gcc 10.3 (assertions)
x86-64 gcc 10.4
x86-64 gcc 10.4 (assertions)
x86-64 gcc 10.5
x86-64 gcc 10.5 (assertions)
x86-64 gcc 11.1
x86-64 gcc 11.1 (assertions)
x86-64 gcc 11.2
x86-64 gcc 11.2 (assertions)
x86-64 gcc 11.3
x86-64 gcc 11.3 (assertions)
x86-64 gcc 11.4
x86-64 gcc 11.4 (assertions)
x86-64 gcc 12.1
x86-64 gcc 12.1 (assertions)
x86-64 gcc 12.2
x86-64 gcc 12.2 (assertions)
x86-64 gcc 12.3
x86-64 gcc 12.3 (assertions)
x86-64 gcc 12.4
x86-64 gcc 12.4 (assertions)
x86-64 gcc 12.5
x86-64 gcc 12.5 (assertions)
x86-64 gcc 13.1
x86-64 gcc 13.1 (assertions)
x86-64 gcc 13.2
x86-64 gcc 13.2 (assertions)
x86-64 gcc 13.3
x86-64 gcc 13.3 (assertions)
x86-64 gcc 13.4
x86-64 gcc 13.4 (assertions)
x86-64 gcc 14.1
x86-64 gcc 14.1 (assertions)
x86-64 gcc 14.2
x86-64 gcc 14.2 (assertions)
x86-64 gcc 14.3
x86-64 gcc 14.3 (assertions)
x86-64 gcc 15.1
x86-64 gcc 15.1 (assertions)
x86-64 gcc 15.2
x86-64 gcc 15.2 (assertions)
x86-64 gcc 3.4.6
x86-64 gcc 4.0.4
x86-64 gcc 4.1.2
x86-64 gcc 4.4.7
x86-64 gcc 4.5.3
x86-64 gcc 4.6.4
x86-64 gcc 4.7.1
x86-64 gcc 4.7.2
x86-64 gcc 4.7.3
x86-64 gcc 4.7.4
x86-64 gcc 4.8.1
x86-64 gcc 4.8.2
x86-64 gcc 4.8.3
x86-64 gcc 4.8.4
x86-64 gcc 4.8.5
x86-64 gcc 4.9.0
x86-64 gcc 4.9.1
x86-64 gcc 4.9.2
x86-64 gcc 4.9.3
x86-64 gcc 4.9.4
x86-64 gcc 5.1
x86-64 gcc 5.2
x86-64 gcc 5.3
x86-64 gcc 5.4
x86-64 gcc 5.5
x86-64 gcc 6.1
x86-64 gcc 6.2
x86-64 gcc 6.3
x86-64 gcc 6.4
x86-64 gcc 6.5
x86-64 gcc 7.1
x86-64 gcc 7.2
x86-64 gcc 7.3
x86-64 gcc 7.4
x86-64 gcc 7.5
x86-64 gcc 8.1
x86-64 gcc 8.2
x86-64 gcc 8.3
x86-64 gcc 8.4
x86-64 gcc 8.5
x86-64 gcc 9.1
x86-64 gcc 9.2
x86-64 gcc 9.3
x86-64 gcc 9.4
x86-64 gcc 9.5
x86-64 icc 13.0.1
x86-64 icc 16.0.3
x86-64 icc 17.0.0
x86-64 icc 18.0.0
x86-64 icc 19.0.0
x86-64 icc 19.0.1
x86-64 icc 2021.1.2
x86-64 icc 2021.10.0
x86-64 icc 2021.2.0
x86-64 icc 2021.3.0
x86-64 icc 2021.4.0
x86-64 icc 2021.5.0
x86-64 icc 2021.6.0
x86-64 icc 2021.7.0
x86-64 icc 2021.7.1
x86-64 icc 2021.8.0
x86-64 icc 2021.9.0
x86-64 icx 2021.1.2
x86-64 icx 2021.2.0
x86-64 icx 2021.3.0
x86-64 icx 2021.4.0
x86-64 icx 2022.0.0
x86-64 icx 2022.1.0
x86-64 icx 2022.2.0
x86-64 icx 2022.2.1
x86-64 icx 2023.0.0
x86-64 icx 2023.1.0
x86-64 icx 2023.2.1
x86-64 icx 2024.0.0
x86-64 icx 2024.1.0
x86-64 icx 2024.2.0
x86-64 icx 2024.2.1
x86-64 icx 2025.0.0
x86-64 icx 2025.0.1
x86-64 icx 2025.0.3
x86-64 icx 2025.0.4
x86-64 icx 2025.1.0
x86-64 icx 2025.1.1
x86-64 icx 2025.2.0
x86-64 icx 2025.2.1
x86-64 icx 2025.2.1
z180-clang 15.0.0
z180-clang 15.0.7
z80-clang 15.0.0
z80-clang 15.0.7
zig c++ 0.10.0
zig c++ 0.11.0
zig c++ 0.12.0
zig c++ 0.12.1
zig c++ 0.13.0
zig c++ 0.14.0
zig c++ 0.14.1
zig c++ 0.15.1
zig c++ 0.6.0
zig c++ 0.7.0
zig c++ 0.7.1
zig c++ 0.8.0
zig c++ 0.9.0
zig c++ trunk
Options
Source code
/* Copyright (C) 2011 Fredrik Johansson Copyright (C) 2013 Tom Bachmann (C++ adaptation) This file is part of FLINT. FLINT is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See <https://www.gnu.org/licenses/>. */ /* Demo FLINT program for incremental multimodular reduction and reconstruction using the Chinese Remainder Theorem. */ #include <iostream> /* Copyright (C) 2013 Tom Bachmann This file is part of FLINT. FLINT is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See <https://www.gnu.org/licenses/>. */ #ifndef CXX_FMPZXX_H #define CXX_FMPZXX_H #include <cstdlib> #include <vector> /* Copyright (C) 2013 Tom Bachmann This file is part of FLINT. FLINT is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See <https://www.gnu.org/licenses/>. */ // This file contains helpers for evaluating expression templates. #ifndef CXX_EVALUATION_TOOLS_H #define CXX_EVALUATION_TOOLS_H #include <iostream> /* Copyright (C) 2009 William Hart This file is part of FLINT. FLINT is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See <https://www.gnu.org/licenses/>. */ #ifndef FLINT_H #define FLINT_H #undef ulong #define ulong ulongxx /* ensure vendor doesn't typedef ulong */ #if !defined(_MSC_VER) #include <sys/param.h> /* for BSD define */ #endif #include <gmp.h> #include <stdarg.h> #include <stdio.h> #include <stdlib.h> /* for alloca on FreeBSD */ #if (!defined(BSD) && !defined(__MINGW64__) && !defined(__MINGW32__) && !defined(_MSC_VER)) || defined(__GNU__) /* MinGW and FreeBSD have alloca, but not alloca.h */ #include <alloca.h> #endif #if defined(__MINGW32__) #include <malloc.h> /* for alloca on MinGW */ #endif #include <limits.h> /* Copyright 1991, 1992, 1993, 1994, 1996, 1997, 1999, 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc. Copyright 2009, 2015, 2016 William Hart Copyright 2011 Fredrik Johansson This file is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This file is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this file; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /* N.B: This file has been adapted from code found in GMP 4.2.1. */ #ifndef FLINT_LONGLONG_H #define FLINT_LONGLONG_H #ifdef __cplusplus extern "C" { #endif /* Undefine to make the ifndef logic below for the fallback work even if the symbols are already defined (e.g. by givaro). */ #undef count_leading_zeros #undef count_trailing_zeros /* 1 if we know that the hardware is strongly-ordered */ #define FLINT_KNOW_STRONG_ORDER 0 /* x86 : 64 bit */ #if (GMP_LIMB_BITS == 64 && defined (__amd64__)) #undef FLINT_KNOW_STRONG_ORDER #define FLINT_KNOW_STRONG_ORDER 1 #define add_ssssaaaaaaaa(s3, s2, s1, s0, a3, a2, a1, a0, b3, b2, b1, b0) \ __asm__ ("addq %11,%q3\n\tadcq %9,%q2\n\tadcq %7,%q1\n\tadcq %5,%q0" \ : "=r" (s3), "=&r" (s2), "=&r" (s1), "=&r" (s0) \ : "0" ((mp_limb_t)(a3)), "rme" ((mp_limb_t)(b3)), \ "1" ((mp_limb_t)(a2)), "rme" ((mp_limb_t)(b2)), \ "2" ((mp_limb_t)(a1)), "rme" ((mp_limb_t)(b1)), \ "3" ((mp_limb_t)(a0)), "rme" ((mp_limb_t)(b0))) \ #define add_sssaaaaaa(sh, sm, sl, ah, am, al, bh, bm, bl) \ __asm__ ("addq %8,%q2\n\tadcq %6,%q1\n\tadcq %4,%q0" \ : "=r" (sh), "=&r" (sm), "=&r" (sl) \ : "0" ((mp_limb_t)(ah)), "rme" ((mp_limb_t)(bh)), \ "1" ((mp_limb_t)(am)), "rme" ((mp_limb_t)(bm)), \ "2" ((mp_limb_t)(al)), "rme" ((mp_limb_t)(bl))) \ #define sub_dddmmmsss(dh, dm, dl, mh, mm, ml, sh, sm, sl) \ __asm__ ("subq %8,%q2\n\tsbbq %6,%q1\n\tsbbq %4,%q0" \ : "=r" (dh), "=&r" (dm), "=&r" (dl) \ : "0" ((mp_limb_t)(mh)), "rme" ((mp_limb_t)(sh)), \ "1" ((mp_limb_t)(mm)), "rme" ((mp_limb_t)(sm)), \ "2" ((mp_limb_t)(ml)), "rme" ((mp_limb_t)(sl))) \ #define add_ssaaaa(sh, sl, ah, al, bh, bl) \ __asm__ ("addq %5,%q1\n\tadcq %3,%q0" \ : "=r" (sh), "=&r" (sl) \ : "0" ((mp_limb_t)(ah)), "rme" ((mp_limb_t)(bh)), \ "%1" ((mp_limb_t)(al)), "rme" ((mp_limb_t)(bl))) #define sub_ddmmss(sh, sl, ah, al, bh, bl) \ __asm__ ("subq %5,%q1\n\tsbbq %3,%q0" \ : "=r" (sh), "=&r" (sl) \ : "0" ((mp_limb_t)(ah)), "rme" ((mp_limb_t)(bh)), \ "1" ((mp_limb_t)(al)), "rme" ((mp_limb_t)(bl))) #define umul_ppmm(w1, w0, u, v) \ __asm__ ("mulq %3" \ : "=a" (w0), "=d" (w1) \ : "%0" ((mp_limb_t)(u)), "rm" ((mp_limb_t)(v))) #define smul_ppmm(w1, w0, u, v) \ __asm__ ("imulq %3" \ : "=a" (w0), "=d" (w1) \ : "%0" ((mp_limb_t)(u)), "rm" ((mp_limb_t)(v))) #define udiv_qrnnd(q, r, n1, n0, dx) \ __asm__ volatile ("divq %4" \ : "=a" (q), "=d" (r) \ : "0" ((mp_limb_t)(n0)), "1" ((mp_limb_t)(n1)), "rm" ((mp_limb_t)(dx))) #define sdiv_qrnnd(q, r, n1, n0, dx) \ __asm__ volatile ("idivq %4" \ : "=a" (q), "=d" (r) \ : "0" ((mp_limb_t)(n0)), "1" ((mp_limb_t)(n1)), "rm" ((mp_limb_t)(dx))) /* bsrq destination must be a 64-bit register, hence mp_limb_t for __cbtmp. */ #define count_leading_zeros(count, x) \ do { \ mp_limb_t __cbtmp; \ FLINT_ASSERT ((x) != 0); \ __asm__ ("bsrq %1,%0" : "=r" (__cbtmp) : "rm" ((mp_limb_t)(x))); \ (count) = __cbtmp ^ (mp_limb_t) 63; \ } while (0) /* bsfq destination must be a 64-bit register, "%q0" forces this in case count is only an int. */ #define count_trailing_zeros(count, x) \ do { \ FLINT_ASSERT ((x) != 0); \ __asm__ ("bsfq %1,%q0" : "=r" (count) : "rm" ((mp_limb_t)(x))); \ } while (0) #define byte_swap(x) \ do { \ __asm__("bswapq %q0" : "=r"(x) : "0"(x)); \ } while (0) #endif /* x86_64 */ /* x86 : 32 bit */ #if (GMP_LIMB_BITS == 32 && (defined (__i386__) \ || defined (__i486__) || defined(__amd64__))) #undef FLINT_KNOW_STRONG_ORDER #define FLINT_KNOW_STRONG_ORDER 1 #define add_ssssaaaaaaaa(s3, s2, s1, s0, a3, a2, a1, a0, b3, b2, b1, b0) \ __asm__ ("addl %11,%k3\n\tadcl %9,%k2\n\tadcl %7,%k1\n\tadcl %5,%k0" \ : "=r" (s3), "=&r" (s2), "=&r" (s1), "=&r" (s0) \ : "0" ((mp_limb_t)(a3)), "g" ((mp_limb_t)(b3)), \ "1" ((mp_limb_t)(a2)), "g" ((mp_limb_t)(b2)), \ "2" ((mp_limb_t)(a1)), "g" ((mp_limb_t)(b1)), \ "3" ((mp_limb_t)(a0)), "g" ((mp_limb_t)(b0))) \ #define add_sssaaaaaa(sh, sm, sl, ah, am, al, bh, bm, bl) \ __asm__ ("addl %8,%k2\n\tadcl %6,%k1\n\tadcl %4,%k0" \ : "=r" (sh), "=r" (sm), "=&r" (sl) \ : "0" ((mp_limb_t)(ah)), "g" ((mp_limb_t)(bh)), \ "1" ((mp_limb_t)(am)), "g" ((mp_limb_t)(bm)), \ "2" ((mp_limb_t)(al)), "g" ((mp_limb_t)(bl))) \ #define sub_dddmmmsss(dh, dm, dl, mh, mm, ml, sh, sm, sl) \ __asm__ ("subl %8,%k2\n\tsbbl %6,%k1\n\tsbbl %4,%k0" \ : "=r" (dh), "=r" (dm), "=&r" (dl) \ : "0" ((mp_limb_t)(mh)), "g" ((mp_limb_t)(sh)), \ "1" ((mp_limb_t)(mm)), "g" ((mp_limb_t)(sm)), \ "2" ((mp_limb_t)(ml)), "g" ((mp_limb_t)(sl))) \ #define add_ssaaaa(sh, sl, ah, al, bh, bl) \ __asm__ ("addl %5,%k1\n\tadcl %3,%k0" \ : "=r" (sh), "=&r" (sl) \ : "0" ((mp_limb_t)(ah)), "g" ((mp_limb_t)(bh)), \ "%1" ((mp_limb_t)(al)), "g" ((mp_limb_t)(bl))) #define sub_ddmmss(sh, sl, ah, al, bh, bl) \ __asm__ ("subl %5,%k1\n\tsbbl %3,%k0" \ : "=r" (sh), "=&r" (sl) \ : "0" ((mp_limb_t)(ah)), "g" ((mp_limb_t)(bh)), \ "1" ((mp_limb_t)(al)), "g" ((mp_limb_t)(bl))) #define umul_ppmm(w1, w0, u, v) \ __asm__ ("mull %3" \ : "=a" (w0), "=d" (w1) \ : "%0" ((mp_limb_t)(u)), "rm" ((mp_limb_t)(v))) #define smul_ppmm(w1, w0, u, v) \ __asm__ ("imull %3" \ : "=a" (w0), "=d" (w1) \ : "%0" ((mp_limb_t)(u)), "rm" ((mp_limb_t)(v))) #define udiv_qrnnd(q, r, n1, n0, dx) \ __asm__ volatile ("divl %4" \ : "=a" (q), "=d" (r) \ : "0" ((mp_limb_t)(n0)), "1" ((mp_limb_t)(n1)), "rm" ((mp_limb_t)(dx))) #define sdiv_qrnnd(q, r, n1, n0, dx) \ __asm__ volatile ("idivl %4" \ : "=a" (q), "=d" (r) \ : "0" ((mp_limb_t)(n0)), "1" ((mp_limb_t)(n1)), "rm" ((mp_limb_t)(dx))) #define count_leading_zeros(count, x) \ do { \ mp_limb_t __cbtmp; \ FLINT_ASSERT ((x) != 0); \ __asm__ ("bsrl %1,%0" : "=r" (__cbtmp) : "rm" ((mp_limb_t)(x))); \ (count) = __cbtmp ^ (mp_limb_t) 31; \ } while (0) #define count_trailing_zeros(count, x) \ do { \ FLINT_ASSERT ((x) != 0); \ __asm__ ("bsfl %1,%0" : "=r" (count) : "rm" ((mp_limb_t)(x))); \ } while (0) #define byte_swap(x) \ do { \ __asm__("bswap %0" : "=r"(x) : "0"(x)); \ } while (0) #endif /* x86 */ /* Itanium */ #if (GMP_LIMB_BITS == 64 && defined (__ia64)) /* This form encourages gcc (pre-release 3.4 at least) to emit predicated "sub r=r,r" and "sub r=r,r,1", giving a 2 cycle latency. The generic code using "al<bl" arithmetically comes out making an actual 0 or 1 in a register, which takes an extra cycle. */ #define sub_ddmmss(sh, sl, ah, al, bh, bl) \ do { \ mp_limb_t __x; \ __x = (al) - (bl); \ if ((mp_limb_t) (al) < (mp_limb_t) (bl)) \ (sh) = (ah) - (bh) - 1; \ else \ (sh) = (ah) - (bh); \ (sl) = __x; \ } while (0) #define count_trailing_zeros(count, x) \ do { \ mp_limb_t __ctz_x = (x); \ __asm__ ("popcnt %0 = %1" \ : "=r" (count) \ : "r" ((__ctz_x-1) & ~__ctz_x)); \ } while (0) /* Do both product parts in assembly, since that gives better code with all gcc versions. Some callers will just use the upper part, and in that situation we waste an instruction, but not any cycles. */ #define umul_ppmm(ph, pl, m0, m1) \ __asm__ ("xma.hu %0 = %2, %3, f0\n\txma.l %1 = %2, %3, f0" \ : "=&f" (ph), "=f" (pl) \ : "f" (m0), "f" (m1)) #endif /* Itanium */ /* ARM */ #if (GMP_LIMB_BITS == 32 && defined (__arm__)) #define add_ssaaaa(sh, sl, ah, al, bh, bl) \ __asm__ ("adds\t%1, %4, %5\n\tadc\t%0, %2, %3" \ : "=r" (sh), "=&r" (sl) \ : "r" (ah), "rI" (bh), "%r" (al), "rI" (bl) : "cc") /* rsbs is only available in ARM and Thumb modes, not in Thumb2 mode */ #if !defined(__thumb2__) #define sub_ddmmss(sh, sl, ah, al, bh, bl) \ do { \ if (__builtin_constant_p (al)) \ { \ if (__builtin_constant_p (ah)) \ __asm__ ("rsbs\t%1, %5, %4\n\trsc\t%0, %3, %2" \ : "=r" (sh), "=&r" (sl) \ : "rI" (ah), "r" (bh), "rI" (al), "r" (bl) : "cc"); \ else \ __asm__ ("rsbs\t%1, %5, %4\n\tsbc\t%0, %2, %3" \ : "=r" (sh), "=&r" (sl) \ : "r" (ah), "rI" (bh), "rI" (al), "r" (bl) : "cc"); \ } \ else if (__builtin_constant_p (ah)) \ { \ if (__builtin_constant_p (bl)) \ __asm__ ("subs\t%1, %4, %5\n\trsc\t%0, %3, %2" \ : "=r" (sh), "=&r" (sl) \ : "rI" (ah), "r" (bh), "r" (al), "rI" (bl) : "cc"); \ else \ __asm__ ("rsbs\t%1, %5, %4\n\trsc\t%0, %3, %2" \ : "=r" (sh), "=&r" (sl) \ : "rI" (ah), "r" (bh), "rI" (al), "r" (bl) : "cc"); \ } \ else if (__builtin_constant_p (bl)) \ { \ if (__builtin_constant_p (bh)) \ __asm__ ("subs\t%1, %4, %5\n\tsbc\t%0, %2, %3" \ : "=r" (sh), "=&r" (sl) \ : "r" (ah), "rI" (bh), "r" (al), "rI" (bl) : "cc"); \ else \ __asm__ ("subs\t%1, %4, %5\n\trsc\t%0, %3, %2" \ : "=r" (sh), "=&r" (sl) \ : "rI" (ah), "r" (bh), "r" (al), "rI" (bl) : "cc"); \ } \ else /* only bh might be a constant */ \ __asm__ ("subs\t%1, %4, %5\n\tsbc\t%0, %2, %3" \ : "=r" (sh), "=&r" (sl) \ : "r" (ah), "rI" (bh), "r" (al), "rI" (bl) : "cc"); \ } while (0) #else #define sub_ddmmss(sh, sl, ah, al, bh, bl) \ do { \ __asm__ ("subs\t%1, %4, %5\n\tsbc\t%0, %2, %3" \ : "=r" (sh), "=&r" (sl) \ : "r" (ah), "r" (bh), "r" (al), "r" (bl) : "cc"); \ } while (0) #endif /* not Thumb2 */ #define umul_ppmm(xh, xl, a, b) \ __asm__ ("umull %0,%1,%2,%3" : "=&r" (xl), "=&r" (xh) : "r" (a), "r" (b)) #define smul_ppmm(xh, xl, a, b) \ __asm__ ("smull %0,%1,%2,%3" : "=&r" (xl), "=&r" (xh) : "r" (a), "r" (b)) #endif /* ARM */ #if defined(__arm64__) #define umul_ppmm(xh, xl, a, b) \ __asm__ ("mul %0,%2,%3\numulh %1,%2,%3" : "=&r" (xl), "=&r" (xh) : "r" (a), "r" (b)) #define smul_ppmm(xh, xl, a, b) \ __asm__ ("mul %0,%2,%3\nsmulh %1,%2,%3" : "=&r" (xl), "=&r" (xh) : "r" (a), "r" (b)) #define add_ssaaaa(sh, sl, ah, al, bh, bl) \ __asm__ ("adds %1,%3,%5\n\tadc %0,%2,%4" \ : "=r" (sh), "=&r" (sl) \ : "r" ((mp_limb_t)(ah)), "r" ((mp_limb_t)(al)), \ "r" ((mp_limb_t)(bh)), "rI" ((mp_limb_t)(bl)) \ : "cc") #define add_sssaaaaaa(sh, sm, sl, ah, am, al, bh, bm, bl) \ __asm__ ("adds %2,%5,%8\n\tadcs %1,%4,%7\n\tadc %0,%3,%6" \ : "=r" (sh), "=&r" (sm), "=&r" (sl) \ : "r" ((mp_limb_t)(ah)), "r" ((mp_limb_t)(am)), "r" ((mp_limb_t)(al)),\ "r" ((mp_limb_t)(bh)), "r" ((mp_limb_t)(bm)), "rI" ((mp_limb_t)(bl)) \ : "cc") #define add_ssssaaaaaaaa(s3, s2, s1, s0, a3, a2, a1, a0, b3, b2, b1, b0) \ __asm__ ("adds %3,%7,%11\n\tadcs %2,%6,%10\n\tadcs %1,%5,%9\n\tadc %0,%4,%8"\ : "=r" (s3), "=&r" (s2), "=&r" (s1), "=&r" (s0) \ : "r" ((mp_limb_t)(a3)), "r" ((mp_limb_t)(a2)), \ "r" ((mp_limb_t)(a1)), "r" ((mp_limb_t)(a0)), \ "r" ((mp_limb_t)(b3)), "r" ((mp_limb_t)(b2)), \ "r" ((mp_limb_t)(b1)), "rI" ((mp_limb_t)(b0)) \ : "cc") #define sub_ddmmss(sh, sl, ah, al, bh, bl) \ __asm__ ("subs %1,%3,%5\n\tsbc %0,%2,%4" \ : "=r" (sh), "=&r" (sl) \ : "r" ((mp_limb_t)(ah)), "r" ((mp_limb_t)(al)), \ "r" ((mp_limb_t)(bh)), "rI" ((mp_limb_t)(bl)) \ : "cc") #define sub_dddmmmsss(sh, sm, sl, ah, am, al, bh, bm, bl) \ __asm__ ("subs %2,%5,%8\n\tsbcs %1,%4,%7\n\tsbc %0,%3,%6" \ : "=r" (sh), "=&r" (sm), "=&r" (sl) \ : "r" ((mp_limb_t)(ah)), "r" ((mp_limb_t)(am)), "r" ((mp_limb_t)(al)),\ "r" ((mp_limb_t)(bh)), "r" ((mp_limb_t)(bm)), "rI" ((mp_limb_t)(bl)) \ : "cc") #endif /* fallback code */ #if !(defined (__i386__) || defined (__i486__) || defined(__amd64__)) #define __BITS4 (GMP_LIMB_BITS/4) #define __ll_B ((mp_limb_t) 1 << (GMP_LIMB_BITS / 2)) #define __ll_lowpart(t) ((mp_limb_t) (t) & (__ll_B - 1)) #define __ll_highpart(t) ((mp_limb_t) (t) >> (GMP_LIMB_BITS / 2)) #define __highbit (~(mp_limb_t)0 ^ ((~(mp_limb_t)0) >> 1)) #ifndef NEED_CLZ_TAB #define NEED_CLZ_TAB #endif #if !(GMP_LIMB_BITS == 32 && defined (__arm__)) #if !(GMP_LIMB_BITS == 64 && defined (__ia64)) #if !defined(__arm64__) #define umul_ppmm(w1, w0, u, v) \ do { \ mp_limb_t __x0, __x1, __x2, __x3; \ mp_limb_t __ul, __vl, __uh, __vh; \ mp_limb_t __u = (u), __v = (v); \ \ __ul = __ll_lowpart (__u); \ __uh = __ll_highpart (__u); \ __vl = __ll_lowpart (__v); \ __vh = __ll_highpart (__v); \ \ __x0 = (mp_limb_t) __ul * __vl; \ __x1 = (mp_limb_t) __ul * __vh; \ __x2 = (mp_limb_t) __uh * __vl; \ __x3 = (mp_limb_t) __uh * __vh; \ \ __x1 += __ll_highpart (__x0);/* this can't give carry */ \ __x1 += __x2; /* but this indeed can */ \ if (__x1 < __x2) /* did we get it? */ \ __x3 += __ll_B; /* yes, add it in the proper pos. */ \ \ (w1) = __x3 + __ll_highpart (__x1); \ (w0) = (__x1 << GMP_LIMB_BITS/2) + __ll_lowpart (__x0); \ } while (0) #endif #endif #endif #if !(GMP_LIMB_BITS == 32 && defined (__arm__)) #if !defined(__arm64__) #define add_ssaaaa(sh, sl, ah, al, bh, bl) \ do { \ mp_limb_t __x; \ __x = (al) + (bl); \ (sh) = (ah) + (bh) + (__x < (al)); \ (sl) = __x; \ } while (0) #endif #endif #if !defined(__arm64__) #define add_sssaaaaaa(sh, sm, sl, ah, am, al, bh, bm, bl) \ do { \ mp_limb_t __t, __u; \ add_ssaaaa(__t, sl, (mp_limb_t) 0, al, (mp_limb_t) 0, bl); \ add_ssaaaa(__u, sm, (mp_limb_t) 0, am, (mp_limb_t) 0, bm); \ add_ssaaaa(sh, sm, ah + bh, sm, __u, __t); \ } while (0) #define add_ssssaaaaaaaa(s3, s2, s1, s0, a3, a2, a1, a0, b3, b2, b1, b0) \ do { \ mp_limb_t __tt; \ add_sssaaaaaa(__tt, s1, s0, (mp_limb_t) 0, a1, a0, (mp_limb_t) 0, b1, b0); \ add_ssaaaa(s3, s2, a3, a2, b3, b2); \ add_ssaaaa(s3, s2, s3, s2, (mp_limb_t) 0, __tt); \ } while (0) #endif #if !((GMP_LIMB_BITS == 64 && defined (__ia64)) || \ (GMP_LIMB_BITS == 32 && defined (__arm__))) #if !defined(__arm64__) #define sub_ddmmss(sh, sl, ah, al, bh, bl) \ do { \ mp_limb_t __x; \ __x = (al) - (bl); \ (sh) = (ah) - (bh) - ((mp_limb_t) (al) < (mp_limb_t) (bl)); \ (sl) = __x; \ } while (0) #endif #endif #if !defined(__arm64__) #define sub_dddmmmsss(dh, dm, dl, mh, mm, ml, sh, sm, sl) \ do { \ mp_limb_t __t, __u; \ sub_ddmmss(__t, dl, (mp_limb_t) 0, ml, (mp_limb_t) 0, sl); \ sub_ddmmss(__u, dm, (mp_limb_t) 0, mm, (mp_limb_t) 0, sm); \ sub_ddmmss(dh, dm, (mh) - (sh), dm, -__u, -__t); \ } while (0) #endif /* MIPS and ARM - Use clz builtins */ /* NOTE: Apple clang version 12.0.5 miscompiles the count_leading_zeros fallback */ #if (defined (__mips__) || defined (__arm__) || defined (__arm64__)) #ifdef _LONG_LONG_LIMB #define count_leading_zeros(count,x) \ do { \ FLINT_ASSERT ((x) != 0); \ (count) = __builtin_clzll (x); \ } while (0) #else #define count_leading_zeros(count,x) \ do { \ FLINT_ASSERT ((x) != 0); \ (count) = __builtin_clzl (x); \ } while (0) #endif #ifdef _LONG_LONG_LIMB #define count_trailing_zeros(count,x) \ do { \ FLINT_ASSERT ((x) != 0); \ (count) = __builtin_ctzll (x); \ } while (0) #else #define count_trailing_zeros(count,x) \ do { \ FLINT_ASSERT ((x) != 0); \ (count) = __builtin_ctzl (x); \ } while (0) #endif #endif /* MIPS, ARM */ #define udiv_qrnnd_int(q, r, n1, n0, d) \ do { \ mp_limb_t __d1, __d0, __q1, __q0, __r1, __r0, __m; \ \ FLINT_ASSERT ((d) != 0); \ FLINT_ASSERT ((n1) < (d)); \ \ __d1 = __ll_highpart (d); \ __d0 = __ll_lowpart (d); \ \ __q1 = (n1) / __d1; \ __r1 = (n1) - __q1 * __d1; \ __m = __q1 * __d0; \ __r1 = __r1 * __ll_B | __ll_highpart (n0); \ if (__r1 < __m) \ { \ __q1--, __r1 += (d); \ if (__r1 >= (d)) /* i.e. we didn't get carry when adding to __r1 */ \ if (__r1 < __m) \ __q1--, __r1 += (d); \ } \ __r1 -= __m; \ \ __q0 = __r1 / __d1; \ __r0 = __r1 - __q0 * __d1; \ __m = __q0 * __d0; \ __r0 = __r0 * __ll_B | __ll_lowpart (n0); \ if (__r0 < __m) \ { \ __q0--, __r0 += (d); \ if (__r0 >= (d)) \ if (__r0 < __m) \ __q0--, __r0 += (d); \ } \ __r0 -= __m; \ \ (q) = __q1 * __ll_B | __q0; \ (r) = __r0; \ } while (0) #ifndef count_leading_zeros #define count_leading_zeros(count, x) \ do { \ mp_limb_t __xr = (x); \ mp_limb_t __a; \ \ if (GMP_LIMB_BITS == 32) \ { \ __a = __xr < ((mp_limb_t) 1 << 2*__BITS4) \ ? (__xr < ((mp_limb_t) 1 << __BITS4) ? 1 : __BITS4 + 1) \ : (__xr < ((mp_limb_t) 1 << 3*__BITS4) ? 2*__BITS4 + 1 \ : 3*__BITS4 + 1); \ } \ else \ { \ for (__a = GMP_LIMB_BITS - 8; __a > 0; __a -= 8) \ if (((__xr >> __a) & 0xff) != 0) \ break; \ ++__a; \ } \ \ (count) = GMP_LIMB_BITS + 1 - __a - __flint_clz_tab[__xr >> __a]; \ } while (0) #endif #if !(GMP_LIMB_BITS == 64 && defined (__ia64)) #ifndef count_trailing_zeros #define count_trailing_zeros(count, x) \ do { \ mp_limb_t __ctz_x = (x); \ mp_limb_t __ctz_c; \ FLINT_ASSERT (__ctz_x != 0); \ count_leading_zeros (__ctz_c, __ctz_x & -__ctz_x); \ (count) = GMP_LIMB_BITS - 1 - __ctz_c; \ } while (0) #endif #endif #define udiv_qrnnd(q, r, n1, n0, d) \ do { \ mp_limb_t __norm; \ count_leading_zeros(__norm, (d)); \ if (__norm) \ { \ udiv_qrnnd_int((q), (r), ((n1) << __norm) + ((n0) >> (GMP_LIMB_BITS - __norm)), (n0) << __norm, (d) << __norm); \ (r) = ((mp_limb_t) (r) >> __norm); \ } else \ udiv_qrnnd_int((q), (r), (n1), (n0), (d)); \ } while (0) #define sdiv_qrnnd(q, r, n1, n0, d) \ do { \ mp_limb_t __n1, __n0, __d; \ mp_limb_t __q, __r; \ unsigned int __sgn_n = 0, __sgn_d = 0; \ if ((n1) & __highbit) \ { \ __n0 = -(n0); \ __n1 = ~(n1) + (__n0 == 0); \ __sgn_n = ~__sgn_n; \ } else \ { \ __n0 = (n0); \ __n1 = (n1); \ } \ if ((d) & __highbit) \ { \ __d = -(d); \ __sgn_d = ~__sgn_d; \ } else \ { \ __d = (d); \ } \ udiv_qrnnd(__q, __r, __n1, __n0, __d); \ q = (__sgn_n == __sgn_d) ? __q : -__q; \ r = (__sgn_n == 0) ? __r : -__r; \ } while (0) #if GMP_LIMB_BITS == 32 #define byte_swap(n) \ do { \ /* swap adjacent bytes */ \ n = (((n & 0xff00ff00) >> 8) | ((n & 0x00ff00ff) << 8)); \ /* swap adjacent words */ \ n = ((n >> 16) | (n << 16)); \ } while (0) #else #define byte_swap(n) \ do { \ /* swap adjacent bytes */ \ n = (((n & 0xff00ff00ff00ff00) >> 8) | ((n & 0x00ff00ff00ff00ff) << 8)); \ /* swap adjacent words */ \ n = (((n & 0xffff0000ffff0000) >> 16) | ((n & 0x0000ffff0000ffff) << 16)); \ /* swap adjacent double words */ \ n = ((n >> 32) | (n << 32)); \ } while (0) #endif /* 64 bits */ #endif /* non x86 fallback code */ /* smul_ppm is defined previously for 32bit arm and for all x86 */ #if !( (GMP_LIMB_BITS == 32 && defined (__arm__)) \ || defined (__i386__) || defined (__i486__) || defined(__amd64__)) #if !defined(__arm64__) #define smul_ppmm(w1, w0, u, v) \ do { \ mp_limb_t __w1; \ mp_limb_t __xm0 = (u), __xm1 = (v); \ umul_ppmm (__w1, w0, __xm0, __xm1); \ (w1) = __w1 - (-(__xm0 >> (FLINT_BITS-1)) & __xm1) \ - (-(__xm1 >> (FLINT_BITS-1)) & __xm0); \ } while (0) #endif #endif /* Branch free variant */ #if 1 #define udiv_qrnnd_preinv(q, r, nh, nl, d, di) \ do { \ mp_limb_t _n2, _n10, _nmask, _nadj, _q1; \ mp_limb_t _xh, _xl; \ _n2 = (nh); \ _n10 = (nl); \ _nmask = (mp_limb_signed_t) (_n10) >> (FLINT_BITS - 1); \ _nadj = _n10 + (_nmask & (d)); \ umul_ppmm (_xh, _xl, di, _n2 - _nmask); \ add_ssaaaa (_xh, _xl, _xh, _xl, _n2, _nadj); \ _q1 = ~_xh; \ umul_ppmm (_xh, _xl, _q1, d); \ add_ssaaaa (_xh, _xl, _xh, _xl, nh, nl); \ _xh -= (d); /* xh = 0 or -1 */ \ (r) = _xl + ((d) & _xh); \ (q) = _xh - _q1; \ } while (0) /* Branched variant, slower on K10 for general inputs */ #else #define udiv_qrnnd_preinv(q, r, nh, nl, d, di) \ do { \ mp_limb_t _q, _ql, _r; \ mp_limb_t _xh, _xl; \ FLINT_ASSERT ((d) != 0); \ umul_ppmm (_q, _ql, (nh), (di)); \ _q += (nh); /* Compensate, di is 2^64 too small */ \ umul_ppmm (_xh, _xl, _q, (d)); \ sub_ddmmss (_xh, _r, (nh), (nl), _xh, _xl); \ if (_xh != 0) \ { \ sub_ddmmss (_xh, _r, _xh, _r, 0, (d)); \ _q += 1; \ if (_xh != 0) \ { \ _r -= (d); \ _q += 1; \ } \ } \ if (_r >= (d)) \ { \ _r -= (d); \ _q += 1; \ } \ (r) = _r; \ (q) = _q; \ } while (0) #endif #ifdef __cplusplus } #endif #endif /* Define if the compiler supports and should use thread-local storage */ #define FLINT_USES_TLS 0 /* Define if the library should be thread-safe, no matter whether FLINT_USES_TLS is used */ #define FLINT_REENTRANT 0 /* Define if -DCMAKE_BUILD_TYPE=Debug was given, to enable some ASSERT()s */ #define FLINT_WANT_ASSERT 0 /* Define if you cpu_set_t in sched.h */ #define FLINT_USES_CPUSET 0 #define FLINT_USES_PTHREAD 0 #define FLINT_USES_BLAS 0 #define FLINT_USES_FENV 0 #ifdef _MSC_VER #define access _access #define strcasecmp _stricmp #define strncasecmp _strnicmp #define alloca _alloca #define MSC_C_(x) #x #define MSC_CC_(x) MSC_C_(x) #define MSC_VERSION "Microsoft C++ (Version " MSC_CC_(_MSC_FULL_VER) ")" #endif #if defined (FLINT_BUILD_DLL) #define FLINT_DLL __declspec(dllexport) #elif defined(MSC_USE_DLL) #define FLINT_DLL __declspec(dllimport) #else #define FLINT_DLL #endif #undef ulong #ifdef FLINT_INLINES_C #define FLINT_INLINE FLINT_DLL #else #define FLINT_INLINE static __inline__ #endif #if FLINT_USES_GC #include <gc.h> #endif #if FLINT_WANT_ASSERT #include <assert.h> #endif #ifdef __cplusplus extern "C" { #endif /* flint version number */ #define __FLINT_VERSION 2 #define __FLINT_VERSION_MINOR 10 #define __FLINT_VERSION_PATCHLEVEL 0 #define FLINT_VERSION "2.10.0" #define __FLINT_RELEASE (__FLINT_VERSION * 10000 + \ __FLINT_VERSION_MINOR * 100 + \ __FLINT_VERSION_PATCHLEVEL) #if __GNU_MP_VERSION < 5 #error GMP 5.0.0 or MPIR 2.6.0 or later are required #endif /* We define alternative key words for "asm" and "inline", allowing the code to be compiled with the "-ansi" flag under GCC */ #ifndef __GNUC__ #define __asm__ asm #define __inline__ inline #endif extern char flint_version[]; #define ulong mp_limb_t #define slong mp_limb_signed_t FLINT_DLL void * flint_malloc(size_t size); FLINT_DLL void * flint_realloc(void * ptr, size_t size); FLINT_DLL void * flint_calloc(size_t num, size_t size); FLINT_DLL void flint_free(void * ptr); typedef void (*flint_cleanup_function_t)(void); FLINT_DLL void flint_register_cleanup_function(flint_cleanup_function_t cleanup_function); FLINT_DLL void flint_cleanup(void); FLINT_DLL void flint_cleanup_master(void); FLINT_DLL void __flint_set_memory_functions(void *(*alloc_func) (size_t), void *(*calloc_func) (size_t, size_t), void *(*realloc_func) (void *, size_t), void (*free_func) (void *)); FLINT_DLL void __flint_get_memory_functions(void *(**alloc_func) (size_t), void *(**calloc_func) (size_t, size_t), void *(**realloc_func) (void *, size_t), void (**free_func) (void *)); #ifdef __GNUC__ #define FLINT_NORETURN __attribute__ ((noreturn)) #else #define FLINT_NORETURN #endif FLINT_DLL FLINT_NORETURN void flint_abort(void); FLINT_DLL void flint_set_abort(FLINT_NORETURN void (*func)(void)); /* flint_abort is calling abort by default * if flint_set_abort is used, then instead of abort this function * is called. EXPERIMENTALLY use at your own risk! * May disappear in future versions. */ #if defined(_WIN64) || defined(__mips64) #if defined(__MINGW64__) #define WORD_FMT "%I64" #define WORD_WIDTH_FMT "%*I64" #else #define WORD_FMT "%ll" #define WORD_WIDTH_FMT "%*ll" #endif #define WORD(xx) (xx##LL) #define UWORD(xx) (xx##ULL) #ifndef FLINT_NO_WORDMAC #define UWORD_MAX ULLONG_MAX #define UWORD_MIN ULLONG_MIN #define WORD_MAX LLONG_MAX #define WORD_MIN LLONG_MIN #endif #else #define WORD_FMT "%l" #define WORD_WIDTH_FMT "%*l" #define WORD(xx) (xx##L) #define UWORD(xx) (xx##UL) #ifndef FLINT_NO_WORDMAC #define UWORD_MAX ULONG_MAX #define UWORD_MIN ULONG_MIN #define WORD_MAX LONG_MAX #define WORD_MIN LONG_MIN #endif #endif #if GMP_LIMB_BITS == 64 #define FLINT_BITS 64 #define FLINT_D_BITS 53 #define FLINT64 1 #else #define FLINT_BITS 32 #define FLINT_D_BITS 31 #endif #define flint_bitcnt_t ulong #if FLINT_USES_TLS #if defined(__GNUC__) && __STDC_VERSION__ >= 201112L && __GNUC__ == 4 && __GNUC_MINOR__ < 9 /* GCC 4.7, 4.8 with -std=gnu11 purport to support C11 via __STDC_VERSION__ but lack _Thread_local */ #define FLINT_TLS_PREFIX __thread #elif __STDC_VERSION__ >= 201112L #define FLINT_TLS_PREFIX _Thread_local #elif defined(_MSC_VER) #define FLINT_TLS_PREFIX __declspec(thread) #elif defined(__GNUC__) #define FLINT_TLS_PREFIX __thread #else #error "thread local prefix defined in C11 or later" #endif #else #define FLINT_TLS_PREFIX #endif FLINT_DLL int flint_get_num_threads(void); FLINT_DLL void flint_set_num_threads(int num_threads); FLINT_DLL void _flint_set_num_workers(int num_workers); FLINT_DLL int flint_set_num_workers(int num_workers); FLINT_DLL void flint_reset_num_workers(int max_workers); FLINT_DLL int flint_set_thread_affinity(int * cpus, slong length); FLINT_DLL int flint_restore_thread_affinity(); int flint_test_multiplier(void); typedef struct { gmp_randstate_t gmp_state; int gmp_init; mp_limb_t __randval; mp_limb_t __randval2; } flint_rand_s; typedef flint_rand_s flint_rand_t[1]; FLINT_INLINE void flint_randinit(flint_rand_t state) { state->gmp_init = 0; #if FLINT64 state->__randval = UWORD(13845646450878251009); state->__randval2 = UWORD(13142370077570254774); #else state->__randval = UWORD(4187301858); state->__randval2 = UWORD(3721271368); #endif } FLINT_INLINE void flint_randseed(flint_rand_t state, ulong seed1, ulong seed2) { state->__randval = seed1; state->__randval2 = seed2; } FLINT_INLINE void flint_get_randseed(ulong * seed1, ulong * seed2, flint_rand_t state) { *seed1 = state->__randval; *seed2 = state->__randval2; } FLINT_INLINE void _flint_rand_init_gmp(flint_rand_t state) { if (!state->gmp_init) { gmp_randinit_default(state->gmp_state); state->gmp_init = 1; } } FLINT_INLINE void flint_randclear(flint_rand_t state) { if (state->gmp_init) gmp_randclear(state->gmp_state); } FLINT_INLINE flint_rand_s * flint_rand_alloc(void) { return (flint_rand_s *) flint_malloc(sizeof(flint_rand_s)); } FLINT_INLINE void flint_rand_free(flint_rand_s * state) { flint_free(state); } #if FLINT_USES_GC #define FLINT_GC_INIT() GC_init() #else #define FLINT_GC_INIT() #endif #define FLINT_TEST_INIT(xxx) \ flint_rand_t xxx; \ FLINT_GC_INIT(); \ flint_randinit(xxx) #define FLINT_TEST_CLEANUP(xxx) \ flint_randclear(xxx); \ flint_cleanup_master(); #if FLINT_WANT_ASSERT #define FLINT_ASSERT(param) assert(param) #else #define FLINT_ASSERT(param) #endif #if defined(__GNUC__) #define FLINT_UNUSED(x) UNUSED_ ## x __attribute__((unused)) #define FLINT_SET_BUT_UNUSED(x) x __attribute__((unused)) #if __GNUC__ >= 4 #define FLINT_WARN_UNUSED __attribute__((warn_unused_result)) #else #define FLINT_WARN_UNUSED #endif #else #define __attribute__(x) #define FLINT_UNUSED(x) x #define FLINT_SET_BUT_UNUSED(x) x #define FLINT_WARN_UNUSED #endif #define FLINT_MAX(x, y) ((x) > (y) ? (x) : (y)) #define FLINT_MIN(x, y) ((x) > (y) ? (y) : (x)) #define FLINT_ABS(x) ((slong)(x) < 0 ? (-(x)) : (x)) #define FLINT_SIGN_EXT(x) (-(ulong)((slong)(x) < 0)) #define FLINT_SGN(x) ((0 < (slong)(x)) - ((slong)(x) < 0)) #define MP_PTR_SWAP(x, y) \ do { \ mp_limb_t * __txxx; \ __txxx = x; \ x = y; \ y = __txxx; \ } while (0) #define SLONG_SWAP(A, B) \ do { \ slong __t_m_p_ = A; \ A = B; \ B = __t_m_p_; \ } while (0) #define ULONG_SWAP(A, B) \ do { \ ulong __t_m_p_ = A; \ A = B; \ B = __t_m_p_; \ } while (0) #define MP_LIMB_SWAP(A, B) \ do { \ mp_limb_t __t_m_p_ = A; \ A = B; \ B = __t_m_p_; \ } while (0) #define DOUBLE_SWAP(A, B) \ do { \ double __t_m_p_ = A; \ A = B; \ B = __t_m_p_; \ } while (0) #define r_shift(in, shift) \ ((shift == FLINT_BITS) ? WORD(0) : ((in) >> (shift))) #define l_shift(in, shift) \ ((shift == FLINT_BITS) ? WORD(0) : ((in) << (shift))) #ifdef NEED_CLZ_TAB FLINT_DLL extern const unsigned char __flint_clz_tab[128]; #endif /* Beware when using the unsigned return value in signed arithmetic */ static __inline__ mp_limb_t FLINT_BIT_COUNT(mp_limb_t x) { mp_limb_t zeros = FLINT_BITS; if (x) count_leading_zeros(zeros, x); return FLINT_BITS - zeros; } #define FLINT_FLOG2(k) (FLINT_BIT_COUNT(k) - 1) #define FLINT_CLOG2(k) FLINT_BIT_COUNT((k) - 1) #define flint_mpn_zero(xxx, nnn) \ do \ { \ slong ixxx; \ for (ixxx = 0; ixxx < (nnn); ixxx++) \ (xxx)[ixxx] = UWORD(0); \ } while (0) #define flint_mpn_copyi(xxx, yyy, nnn) \ do { \ slong ixxx; \ for (ixxx = 0; ixxx < (nnn); ixxx++) \ (xxx)[ixxx] = (yyy)[ixxx]; \ } while (0) #define flint_mpn_copyd(xxx, yyy, nnn) \ do { \ slong ixxx; \ for (ixxx = nnn - 1; ixxx >= 0; ixxx--) \ (xxx)[ixxx] = (yyy)[ixxx]; \ } while (0) #define flint_mpn_store(xxx, nnn, yyy) \ do \ { \ slong ixxx; \ for (ixxx = 0; ixxx < nnn; ixxx++) \ (xxx)[ixxx] = yyy; \ } while (0) /* common usage of flint_malloc */ #define FLINT_ARRAY_ALLOC(n, T) (T *) flint_malloc((n)*sizeof(T)) #define FLINT_ARRAY_REALLOC(p, n, T) (T *) flint_realloc(p, (n)*sizeof(T)) /* temporary allocation */ #define TMP_INIT \ typedef struct __tmp_struct { \ void * block; \ struct __tmp_struct * next; \ } __tmp_t; \ __tmp_t * __tmp_root; \ __tmp_t * __tpx #define TMP_START \ __tmp_root = NULL #if FLINT_WANT_ASSERT #define TMP_ALLOC(size) \ (__tpx = (__tmp_t *) alloca(sizeof(__tmp_t)), \ __tpx->next = __tmp_root, \ __tmp_root = __tpx, \ __tpx->block = flint_malloc(size)) #else #define TMP_ALLOC(size) \ (((size) > 8192) ? \ (__tpx = (__tmp_t *) alloca(sizeof(__tmp_t)), \ __tpx->next = __tmp_root, \ __tmp_root = __tpx, \ __tpx->block = flint_malloc(size)) : \ alloca(size)) #endif #define TMP_ARRAY_ALLOC(n, T) (T *) TMP_ALLOC((n)*sizeof(T)) #define TMP_END \ while (__tmp_root) { \ flint_free(__tmp_root->block); \ __tmp_root = __tmp_root->next; \ } /* compatibility between gmp and mpir */ #ifndef mpn_com_n #define mpn_com_n mpn_com #endif #ifndef mpn_neg_n #define mpn_neg_n mpn_neg #endif #ifndef mpn_tdiv_q /* substitute for mpir's mpn_tdiv_q */ static __inline__ void mpn_tdiv_q(mp_ptr qp, mp_srcptr np, mp_size_t nn, mp_srcptr dp, mp_size_t dn) { mp_ptr _scratch; TMP_INIT; TMP_START; _scratch = (mp_ptr) TMP_ALLOC(dn * sizeof(mp_limb_t)); mpn_tdiv_qr(qp, _scratch, 0, np, nn, dp, dn); TMP_END; } #endif /* Newton iteration macros */ #define FLINT_NEWTON_INIT(from, to) \ { \ slong __steps[FLINT_BITS], __i, __from, __to; \ __steps[__i = 0] = __to = (to); \ __from = (from); \ while (__to > __from) \ __steps[++__i] = (__to = (__to + 1) / 2); \ #define FLINT_NEWTON_BASECASE(bc_to) { slong bc_to = __to; #define FLINT_NEWTON_END_BASECASE } #define FLINT_NEWTON_LOOP(step_from, step_to) \ { \ for (__i--; __i >= 0; __i--) \ { \ slong step_from = __steps[__i+1]; \ slong step_to = __steps[__i]; \ #define FLINT_NEWTON_END_LOOP }} #define FLINT_NEWTON_END } FLINT_DLL int parse_fmt(int * floating, const char * fmt); FLINT_DLL int flint_printf(const char * str, ...); /* flint version of printf */ FLINT_DLL int flint_vprintf(const char * str, va_list ap); /* va_list version of flint_printf */ FLINT_DLL int flint_fprintf(FILE * f, const char * str, ...); /* flint version of fprintf */ FLINT_DLL int flint_sprintf(char * s, const char * str, ...); /* flint version of sprintf */ FLINT_DLL int flint_scanf(const char * str, ...); /* flint version of scanf */ FLINT_DLL int flint_fscanf(FILE * f, const char * str, ...); /* flint version of fscanf */ FLINT_DLL int flint_sscanf(const char * s, const char * str, ...); /* flint version of sscanf */ FLINT_INLINE slong flint_mul_sizes(slong x, slong y) { ulong hi, lo; umul_ppmm(hi, lo, (ulong) x, (ulong) y); if (hi != 0 || lo > WORD_MAX) { flint_printf("Exception (flint). Overflow creating size %wd x %wd object.\n", x, y); flint_abort(); } return lo; } /* Copyright (C) 2013 William Hart This file is part of FLINT. FLINT is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See <https://www.gnu.org/licenses/>. */ #include <stdio.h> #include <stdlib.h> #include <gmp.h> #include <limits.h> #ifndef GMP_COMPAT_H #define GMP_COMPAT_H #define FLINT_MPZ_REALLOC(z, len) \ ((len) > ((z)->_mp_alloc) \ ? (mp_ptr) _mpz_realloc(z, len) \ : ((z)->_mp_d)) #define FLINT_MPZ_PTR_SWAP(a, b) \ do { \ mpz_ptr __tmp = (a); \ (a) = (b); \ (b) = __tmp; \ } while (0) /* mpn_get_d -- limbs to double conversion. THE FUNCTIONS IN THIS FILE ARE FOR INTERNAL USE ONLY. THEY'RE ALMOST CERTAIN TO BE SUBJECT TO INCOMPATIBLE CHANGES OR DISAPPEAR COMPLETELY IN FUTURE GNU MP RELEASES. Copyright 2003, 2004 Free Software Foundation, Inc. Copyright 2021 William Hart (adaption to Flint) This file is part of the GNU MP Library. The GNU MP Library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. The GNU MP Library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with the GNU MP Library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #define CONST_1024 (1024) #define CONST_NEG_1023 (-1023) #define CONST_NEG_1022_SUB_53 (-1022 - 53) /* Return the value {ptr,size}*2^exp, and negative if sign<0. Must have size>=1, and a non-zero high limb ptr[size-1]. {ptr,size} is truncated towards zero. This is consistent with other gmp conversions, like mpz_set_f or mpz_set_q, and is easy to implement and test. In the past conversions had attempted (imperfectly) to let the hardware float rounding mode take effect, but that gets tricky since multiple roundings need to be avoided, or taken into account, and denorms mean the effective precision of the mantissa is not constant. (For reference, mpz_get_d on IEEE systems was ok, except it operated on the absolute value. mpf_get_d and mpq_get_d suffered from multiple roundings and from not always using enough bits to get the rounding right.) It's felt that GMP is not primarily concerned with hardware floats, and really isn't enhanced by getting involved with hardware rounding modes (which could even be some weird unknown style), so something unambiguous and straightforward is best. The IEEE code below is the usual case, it knows either a 32-bit or 64-bit limb and is done with shifts and masks. The 64-bit case in particular should come out nice and compact. The generic code works one bit at a time, which will be quite slow, but should support any binary-based "double" and be safe against any rounding mode. Note in particular it works on IEEE systems too. Traps: Hardware traps for overflow to infinity, underflow to zero, or unsupported denorms may or may not be taken. The IEEE code works bitwise and so probably won't trigger them, the generic code works by float operations and so probably will. This difference might be thought less than ideal, but again its felt straightforward code is better than trying to get intimate with hardware exceptions (of perhaps unknown nature). Not done: mpz_get_d in the past handled size==1 with a cast limb->double. This might still be worthwhile there (for up to the mantissa many bits), but for mpn_get_d here, the cost of applying "exp" to the resulting exponent would probably use up any benefit a cast may have over bit twiddling. Also, if the exponent is pushed into denorm range then bit twiddling is the only option, to ensure the desired truncation is obtained. Other: For reference, note that HPPA 8000, 8200, 8500 and 8600 trap FCNV,UDW,DBL to the kernel for values >= 2^63. This makes it slow, and worse the Linux kernel (what versions?) apparently uses untested code in its trap handling routines, and gets the sign wrong. We don't use such a limb to double cast, neither in the IEEE or generic code. */ /* assumes unsigned int is at least 32 bits */ #if defined (FLINT_BIG_ENDIAN) && FLINT_BIG_ENDIAN == 1 union ieee_double_extract { struct { unsigned int sig:1; unsigned int exp:11; unsigned int manh:20; unsigned int manl:32; } s; double d; }; #else union ieee_double_extract { struct { unsigned int manl:32; unsigned int manh:20; unsigned int exp:11; unsigned int sig:1; } s; double d; }; #endif static __inline__ double flint_mpn_get_d (mp_srcptr ptr, mp_size_t size, mp_size_t sign, long exp) { FLINT_ASSERT (size >= 0); FLINT_ASSERT (size == 0 || ptr[size-1] != 0); if (size == 0) return 0.0; /* Adjust exp to a radix point just above {ptr,size}, guarding against overflow. After this exp can of course be reduced to anywhere within the {ptr,size} region without underflow. */ if ((unsigned long) (FLINT_BITS * size) > (unsigned long) (LONG_MAX - exp)) { goto ieee_infinity; /* generic */ exp = LONG_MAX; } else { exp += FLINT_BITS * size; } #define ONE_LIMB (FLINT_BITS == 64) #define TWO_LIMBS (FLINT_BITS == 32) { union ieee_double_extract u; mp_limb_t m0, m1, m2, rmask; int lshift, rshift; m0 = ptr[size-1]; /* high limb */ m1 = (size >= 2 ? ptr[size-2] : 0); /* second highest limb */ count_leading_zeros (lshift, m0); /* relative to just under high non-zero bit */ exp -= lshift + 1; if (ONE_LIMB) { /* lshift to have high of m0 non-zero, and collapse nails */ rshift = FLINT_BITS - lshift; rmask = lshift == 0 ? 0 : UWORD_MAX; m0 = (m0 << lshift) | ((m1 >> rshift) & rmask); /* rshift back to have bit 53 of m0 the high non-zero */ m0 >>= 11; } else /* TWO_LIMBS */ { m2 = (size >= 3 ? ptr[size-3] : 0); /* third highest limb */ /* lshift to have high of m0:m1 non-zero, collapse nails from m0 */ rshift = FLINT_BITS - lshift; rmask = (lshift == 0 ? 0 : UWORD_MAX); m0 = (m0 << lshift) | ((m1 >> rshift) & rmask); m1 = (m1 << lshift) | ((m2 >> rshift) & rmask); /* rshift back to have bit 53 of m0:m1 the high non-zero */ m1 = (m1 >> 11) | (m0 << (FLINT_BITS-11)); m0 >>= 11; } if (exp >= CONST_1024) { /* overflow, return infinity */ ieee_infinity: m0 = 0; m1 = 0; exp = 1024; } else if (exp <= CONST_NEG_1023) { if (exp <= CONST_NEG_1022_SUB_53) return 0.0; /* denorm underflows to zero */ rshift = -1022 - exp; FLINT_ASSERT (rshift > 0 && rshift < 53); if (ONE_LIMB) { m0 >>= rshift; } else /* TWO_LIMBS */ { if (rshift >= 32) { m1 = m0; m0 = 0; rshift -= 32; } lshift = FLINT_BITS - rshift; m1 = (m1 >> rshift) | (rshift == 0 ? 0 : m0 << lshift); m0 >>= rshift; } exp = -1023; } if (ONE_LIMB) { #if FLINT_BITS > 32 /* avoid compiler warning about big shift */ u.s.manh = m0 >> 32; #endif u.s.manl = m0; } else /* TWO_LIMBS */ { u.s.manh = m0; u.s.manl = m1; } u.s.exp = exp + 1023; u.s.sig = (sign < 0); return u.d; } } #if WORD_MAX != LONG_MAX && !defined(__MPIR_VERSION) #define FLINT_MOCK_MPZ_UI(xxx, yyy) \ __mpz_struct (xxx)[1] = {{ 1, 0, NULL }}; \ do { \ (xxx)->_mp_d = (mp_ptr) &(yyy); \ if ((yyy) > 0) \ (xxx)->_mp_size = 1; \ }while (0) #define FLINT_MOCK_MPZ_SI(xxx, yyy) \ __mpz_struct (xxx)[1] = {{ 1, 0, NULL }}; \ do { \ (xxx)->_mp_d = (mp_ptr) &(yyy); \ if ((yyy) < 0) (xxx)->_mp_size = -1, (yyy) = -(yyy); \ else (xxx)->_mp_size = (yyy) != 0; \ } while (0) #define flint_mpz_get_si(xxx) \ ((xxx)->_mp_size == 0 ? (slong) WORD(0) : \ ((xxx)->_mp_size > 0 ? (slong) (xxx)->_mp_d[0] : (slong) -(xxx)->_mp_d[0])) #define flint_mpz_get_ui(xxx) \ ((xxx)->_mp_size == 0 ? UWORD(0) : (xxx)->_mp_d[0]) static __inline__ void flint_mpz_set_si(mpz_ptr r, slong s) { /* GMP 6.2 lazily performs allocation, deal with that if necessary (in older GMP versions, this code is simply never triggered) */ if (r->_mp_alloc == 0) { r->_mp_d = (mp_ptr) flint_malloc(sizeof(mp_limb_t)); r->_mp_alloc = 1; } if (s < 0) { r->_mp_size = -1; r->_mp_d[0] = -s; } else { r->_mp_size = s != 0; r->_mp_d[0] = s; } } static __inline__ void flint_mpz_set_ui(mpz_ptr r, ulong u) { /* GMP 6.2 lazily performs allocation, deal with that if necessary (in older GMP versions, this code is simply never triggered) */ if (r->_mp_alloc == 0) { r->_mp_d = (mp_ptr) flint_malloc(sizeof(mp_limb_t)); r->_mp_alloc = 1; } r->_mp_d[0] = u; r->_mp_size = u != 0; } static __inline__ void flint_mpz_init_set_si(mpz_ptr r, slong s) { r->_mp_d = (mp_ptr) flint_malloc(sizeof(mp_limb_t)); r->_mp_alloc = 1; if (s < 0) { r->_mp_size = -1; r->_mp_d[0] = -s; } else { r->_mp_size = s != 0; r->_mp_d[0] = s; } } static __inline__ void flint_mpz_init_set_ui(mpz_ptr r, ulong u) { r->_mp_d = (mp_ptr) flint_malloc(sizeof(mp_limb_t)); r->_mp_alloc = 1; r->_mp_d[0] = u; r->_mp_size = u != 0; } static __inline__ void flint_mpz_add_ui(mpz_ptr a, mpz_srcptr b, ulong c) { FLINT_MOCK_MPZ_UI(tc, c); mpz_add(a, b, tc); } static __inline__ void flint_mpz_sub_ui(mpz_ptr a, mpz_srcptr b, ulong c) { FLINT_MOCK_MPZ_UI(tc, c); mpz_sub(a, b, tc); } static __inline__ void flint_mpz_mul_ui(mpz_ptr a, mpz_srcptr b, ulong c) { FLINT_MOCK_MPZ_UI(tc, c); mpz_mul(a, b, tc); } static __inline__ void flint_mpz_mul_si(mpz_ptr a, mpz_srcptr b, slong c) { FLINT_MOCK_MPZ_SI(tc, c); mpz_mul(a, b, tc); } static __inline__ void flint_mpz_addmul_ui(mpz_ptr a, mpz_srcptr b, ulong c) { FLINT_MOCK_MPZ_UI(tc, c); mpz_addmul(a, b, tc); } static __inline__ void flint_mpz_submul_ui(mpz_ptr a, mpz_srcptr b, ulong c) { FLINT_MOCK_MPZ_UI(tc, c); mpz_submul(a, b, tc); } static __inline__ void flint_mpz_ui_sub(mpz_ptr a, ulong b, mpz_srcptr c) { FLINT_MOCK_MPZ_UI(tb, b); mpz_sub(a, tb, c); } static __inline__ void flint_mpz_ui_pow_ui(mpz_ptr a, ulong b, ulong c) { FLINT_MOCK_MPZ_UI(tb, b); mpz_pow_ui(a, tb, c); } static __inline__ void flint_mpz_divexact_ui(mpz_ptr a, mpz_srcptr b, ulong c) { FLINT_MOCK_MPZ_UI(tc, c); mpz_divexact(a, b, tc); } static __inline__ int flint_mpz_divisible_ui_p(mpz_srcptr a, ulong c) { FLINT_MOCK_MPZ_UI(tc, c); return mpz_divisible_p(a, tc); } static __inline__ int flint_mpz_congruent_ui_p(mpz_srcptr a, ulong b, ulong c) { FLINT_MOCK_MPZ_UI(tc, c); { FLINT_MOCK_MPZ_UI(tb, b); return mpz_congruent_p(a, tb, tc); } } static __inline__ int flint_mpz_cmp_ui(mpz_srcptr a, ulong c) { FLINT_MOCK_MPZ_UI(tc, c); return mpz_cmp(a, tc); } static __inline__ int flint_mpz_cmp_si(mpz_srcptr a, slong c) { FLINT_MOCK_MPZ_SI(tc, c); return mpz_cmp(a, tc); } static __inline__ int flint_mpq_cmp_si(mpq_srcptr a, slong b, ulong c) { mpq_t tq; int res; FLINT_MOCK_MPZ_SI(tb, b); { FLINT_MOCK_MPZ_UI(tc, c); mpq_init(tq); mpq_set_num(tq, tb); mpq_set_den(tq, tc); res = mpq_cmp(a, tq); mpq_clear(tq); return res; } } static __inline__ int flint_mpq_cmp_ui(mpq_srcptr a, ulong b, ulong c) { mpq_t tq; int res; FLINT_MOCK_MPZ_UI(tb, b); { FLINT_MOCK_MPZ_UI(tc, c); mpq_init(tq); mpq_set_num(tq, tb); mpq_set_den(tq, tc); res = mpq_cmp(a, tq); mpq_clear(tq); return res; } } static __inline__ void flint_mpq_set_si(mpq_ptr a, slong b, ulong c) { FLINT_MOCK_MPZ_SI(tb, b); { FLINT_MOCK_MPZ_UI(tc, c); mpq_set_num(a, tb); mpq_set_den(a, tc); } } static __inline__ void flint_mpq_set_ui(mpq_ptr a, ulong b, ulong c) { FLINT_MOCK_MPZ_UI(tb, b); { FLINT_MOCK_MPZ_UI(tc, c); mpq_set_num(a, tb); mpq_set_den(a, tc); } } static __inline__ ulong flint_mpz_cdiv_q_ui(mpz_ptr q, mpz_srcptr n, ulong c) { if (FLINT_BIT_COUNT(c) <= 32) return (ulong) mpz_cdiv_q_ui(q, n, (unsigned long) c); else { ulong r; mpz_t rz; mpz_init(rz); FLINT_MOCK_MPZ_UI(tc, c); mpz_cdiv_qr(q, rz, n, tc); r = flint_mpz_get_ui(rz); mpz_clear(rz); return r; } } static __inline__ ulong flint_mpz_fdiv_q_ui(mpz_ptr q, mpz_srcptr n, ulong c) { if (FLINT_BIT_COUNT(c) <= 32) return (ulong) mpz_fdiv_q_ui(q, n, (unsigned long) c); else { ulong r; mpz_t rz; mpz_init(rz); FLINT_MOCK_MPZ_UI(tc, c); mpz_fdiv_qr(q, rz, n, tc); r = flint_mpz_get_ui(rz); mpz_clear(rz); return r; } } static __inline__ ulong flint_mpz_tdiv_q_ui(mpz_ptr q, mpz_srcptr n, ulong c) { if (FLINT_BIT_COUNT(c) <= 32) return (ulong) mpz_tdiv_q_ui(q, n, (unsigned long) c); else { ulong r; mpz_t rz; mpz_init(rz); FLINT_MOCK_MPZ_UI(tc, c); mpz_tdiv_qr(q, rz, n, tc); r = flint_mpz_get_ui(rz); mpz_clear(rz); return r; } } static __inline__ ulong flint_mpz_cdiv_r_ui(mpz_ptr r, mpz_srcptr n, ulong c) { FLINT_MOCK_MPZ_UI(tc, c); mpz_cdiv_r(r, n, tc); return flint_mpz_get_ui(r); } static __inline__ ulong flint_mpz_fdiv_r_ui(mpz_ptr r, mpz_srcptr n, ulong c) { FLINT_MOCK_MPZ_UI(tc, c); mpz_fdiv_r(r, n, tc); return flint_mpz_get_ui(r); } static __inline__ ulong flint_mpz_tdiv_r_ui(mpz_ptr r, mpz_srcptr n, ulong c) { FLINT_MOCK_MPZ_UI(tc, c); mpz_tdiv_r(r, n, tc); return flint_mpz_get_ui(r); } static __inline__ ulong flint_mpz_cdiv_qr_ui(mpz_ptr q, mpz_ptr r, mpz_srcptr n, ulong c) { FLINT_MOCK_MPZ_UI(tc, c); mpz_cdiv_qr(q, r, n, tc); return flint_mpz_get_ui(r); } static __inline__ ulong flint_mpz_fdiv_qr_ui(mpz_ptr q, mpz_ptr r, mpz_srcptr n, ulong c) { FLINT_MOCK_MPZ_UI(tc, c); mpz_fdiv_qr(q, r, n, tc); return flint_mpz_get_ui(r); } static __inline__ ulong flint_mpz_tdiv_qr_ui(mpz_ptr q, mpz_ptr r, mpz_srcptr n, ulong c) { FLINT_MOCK_MPZ_UI(tc, c); mpz_tdiv_qr(q, r, n, tc); return flint_mpz_get_ui(r); } static __inline__ ulong flint_mpz_cdiv_ui(mpz_srcptr n, ulong c) { mpz_t r; ulong res; mpz_init(r); FLINT_MOCK_MPZ_UI(tc, c); mpz_cdiv_r(r, n, tc); res = flint_mpz_get_ui(r); mpz_clear(r); return res; } static __inline__ ulong flint_mpz_fdiv_ui(mpz_srcptr n, ulong c) { mpz_t r; ulong res; mpz_init(r); FLINT_MOCK_MPZ_UI(tc, c); mpz_fdiv_r(r, n, tc); res = flint_mpz_get_ui(r); mpz_clear(r); return res; } static __inline__ ulong flint_mpz_tdiv_ui(mpz_srcptr n, ulong c) { mpz_t r; ulong res; mpz_init(r); FLINT_MOCK_MPZ_UI(tc, c); mpz_tdiv_r(r, n, tc); res = flint_mpz_get_ui(r); mpz_clear(r); return res; } static __inline__ ulong flint_mpz_mod_ui(mpz_ptr r, mpz_srcptr n, ulong c) { FLINT_MOCK_MPZ_UI(tc, c); mpz_fdiv_r(r, n, tc); return flint_mpz_get_ui(r); } static __inline__ void flint_mpz_powm_ui(mpz_ptr r, mpz_srcptr b, ulong exp, mpz_srcptr mod) { FLINT_MOCK_MPZ_UI(texp, exp); mpz_powm(r, b, texp, mod); } static __inline__ void flint_mpz_pow_ui(mpz_ptr r, mpz_srcptr b, ulong exp) { if (exp >= (UWORD(1) << 32)) { printf("Exception (flint_mpz_pow_ui). Power too large.\n"); flint_abort(); } mpz_pow_ui(r, b, (unsigned long) exp); } static __inline__ void flint_mpz_fac_ui(mpz_ptr r, ulong n) { if (n >= (UWORD(1) << 32)) { printf("Exception (flint_mpz_fac_ui). Value n too large.\n"); flint_abort(); } mpz_fac_ui(r, (unsigned long) n); } static __inline__ void flint_mpz_bin_uiui(mpz_ptr r, ulong n, ulong k) { if (n >= (UWORD(1) << 32)) { printf("Exception (flint_mpz_bin_uiui). Value n too large.\n"); flint_abort(); } if (k >= (UWORD(1) << 32)) { printf("Exception (flint_mpz_bin_uiui). Value k too large.\n"); flint_abort(); } mpz_bin_uiui(r, (unsigned long) n, (unsigned long) k); } static __inline__ void flint_mpz_fib_ui(mpz_ptr r, ulong n) { if (n >= (UWORD(1) << 32)) { printf("Exception (flint_mpz_fib_ui). Value n too large.\n"); flint_abort(); } mpz_fib_ui(r, (unsigned long) n); } /* mpf_set_si() -- Assign a float from a signed int. Copyright 1993, 1994, 1995, 2000, 2001, 2002, 2004 Free Software Foundation, Inc. Copyright 2015 William Hart. This file is part of the GNU MP Library. The GNU MP Library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. The GNU MP Library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with the GNU MP Library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ static __inline__ void flint_mpf_set_si (mpf_ptr dest, slong val) { mp_size_t size; mp_limb_t vl; vl = (mp_limb_t) (val >= 0 ? val : -val); dest->_mp_d[0] = vl; size = vl != 0; dest->_mp_exp = size; dest->_mp_size = val >= 0 ? size : -size; } /* mpf_set_ui() -- Assign a float from an unsigned int. Copyright 1993, 1994, 1995, 2001, 2002, 2004 Free Software Foundation, Inc. Copyright 2015 William Hart This file is part of the GNU MP Library. The GNU MP Library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. The GNU MP Library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with the GNU MP Library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ static __inline__ void flint_mpf_set_ui(mpf_ptr f, ulong val) { mp_size_t size; f->_mp_d[0] = val; size = val != 0; f->_mp_exp = f->_mp_size = size; } /* mpf_get_si -- mpf to long conversion Copyright 2001, 2002, 2004 Free Software Foundation, Inc. Copyright 2015 William Hart This file is part of the GNU MP Library. The GNU MP Library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. The GNU MP Library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with the GNU MP Library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ static __inline__ slong flint_mpf_get_si (mpf_srcptr f) { mp_exp_t exp; mp_size_t size, abs_size; mp_srcptr fp; mp_limb_t fl; exp = f->_mp_exp; size = f->_mp_size; fp = f->_mp_d; /* fraction alone truncates to zero this also covers zero, since we have exp==0 for zero */ if (exp <= 0) return WORD(0); /* there are some limbs above the radix point */ fl = 0; abs_size = FLINT_ABS(size); if (abs_size >= exp) fl = fp[abs_size-exp]; if (size > 0) return fl; else /* this form necessary to correctly handle -0x80..00 */ return ~ (fl - 1); } /* mpf_cmp_ui -- Compare a float with an unsigned integer. Copyright 1993, 1994, 1995, 1999, 2001, 2002 Free Software Foundation, Inc. This file is part of the GNU MP Library. The GNU MP Library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. The GNU MP Library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with the GNU MP Library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ static __inline__ int flint_mpf_cmp_ui(mpf_srcptr u, ulong vval) { mp_srcptr up; mp_size_t usize; mp_exp_t uexp; mp_limb_t ulimb; uexp = u->_mp_exp; usize = u->_mp_size; if (usize < 0) return -1; if (vval == 0) return usize != 0; if (uexp > 1) return 1; if (uexp < 1) return -1; up = u->_mp_d; ulimb = up[usize - 1]; usize--; if (ulimb > vval) return 1; else if (ulimb < vval) return -1; while (*up == 0) { up++; usize--; } if (usize > 0) return 1; return 0; } /* mpf_fits_s*_p -- test whether an mpf fits a C signed type. Copyright 2001, 2002 Free Software Foundation, Inc. This file is part of the GNU MP Library. The GNU MP Library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. The GNU MP Library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with the GNU MP Library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ static __inline__ int flint_mpf_fits_slong_p(mpf_srcptr f) { mp_size_t fs, fn; mp_srcptr fp; mp_exp_t exp; mp_limb_t fl; fs = f->_mp_size; if (fs == 0) return 1; /* zero fits */ exp = f->_mp_exp; if (exp < 1) return 1; /* -1 < f < 1 truncates to zero, so fits */ fp = f->_mp_d; fn = FLINT_ABS(fs); if (exp == 1) { fl = fp[fn-1]; } else return 0; return fl <= (fs >= 0 ? (mp_limb_t) WORD_MAX : - (mp_limb_t) WORD_MIN); } #else #define flint_mpz_get_si mpz_get_si #define flint_mpz_get_ui mpz_get_ui #define flint_mpz_set_si mpz_set_si #define flint_mpz_set_ui mpz_set_ui #define flint_mpz_init_set_si mpz_init_set_si #define flint_mpz_init_set_ui mpz_init_set_ui #define flint_mpz_add_ui mpz_add_ui #define flint_mpz_sub_ui mpz_sub_ui #define flint_mpz_mul_si mpz_mul_si #define flint_mpz_mul_ui mpz_mul_ui #define flint_mpz_addmul_ui mpz_addmul_ui #define flint_mpz_submul_ui mpz_submul_ui #define flint_mpz_ui_sub mpz_ui_sub #define flint_mpz_ui_pow_ui mpz_ui_pow_ui #define flint_mpz_cdiv_q_ui mpz_cdiv_q_ui #define flint_mpz_cdiv_r_ui mpz_cdiv_r_ui #define flint_mpz_cdiv_qr_ui mpz_cdiv_qr_ui #define flint_mpz_cdiv_ui mpz_cdiv_ui #define flint_mpz_fdiv_q_ui mpz_fdiv_q_ui #define flint_mpz_fdiv_r_ui mpz_fdiv_r_ui #define flint_mpz_fdiv_qr_ui mpz_fdiv_qr_ui #define flint_mpz_fdiv_ui mpz_fdiv_ui #define flint_mpz_tdiv_q_ui mpz_tdiv_q_ui #define flint_mpz_tdiv_r_ui mpz_tdiv_r_ui #define flint_mpz_tdiv_qr_ui mpz_tdiv_qr_ui #define flint_mpz_tdiv_ui mpz_tdiv_ui #define flint_mpz_mod_ui mpz_mod_ui #define flint_mpz_divexact_ui mpz_divexact_ui #define flint_mpz_divisible_ui_p mpz_divisible_ui_p #define flint_mpz_congruent_ui_p mpz_congruent_ui_p #define flint_mpz_powm_ui mpz_powm_ui #define flint_mpz_pow_ui mpz_pow_ui #define flint_mpz_fac_ui mpz_fac_ui #define flint_mpz_bin_uiui mpz_bin_uiui #define flint_mpz_fib_ui mpz_fib_ui #define flint_mpz_cmp_si mpz_cmp_si #define flint_mpz_cmp_ui mpz_cmp_ui #define flint_mpq_cmp_si mpq_cmp_si #define flint_mpq_cmp_ui mpq_cmp_ui #define flint_mpq_set_si mpq_set_si #define flint_mpq_set_ui mpq_set_ui #define flint_mpf_set_si mpf_set_si #define flint_mpf_set_ui mpf_set_ui #define flint_mpf_get_si mpf_get_si #define flint_mpf_cmp_ui mpf_cmp_ui #define flint_mpf_fits_slong_p mpf_fits_slong_p #endif #if WORD_MAX == LONG_MAX #define flint_mpf_get_d_2exp mpf_get_d_2exp #else /* double mpf_get_d_2exp (signed long int *exp, mpf_t src). Copyright 2001, 2002, 2003, 2004 Free Software Foundation, Inc. This file is part of the GNU MP Library. The GNU MP Library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. The GNU MP Library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with the GNU MP Library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /* This function is only required for MPIR >= 3.0.0 and for GMP, but we include unconditionally when sizeof(ulong) != sizeof(unsigned long) */ static __inline__ double flint_mpf_get_d_2exp(slong * exp2, mpf_srcptr src) { mp_size_t size, abs_size; mp_limb_t * ptr; int cnt; slong exp; size = src->_mp_size; if (size == 0) { *exp2 = 0; return 0.0; } ptr = src->_mp_d; abs_size = FLINT_ABS(size); count_leading_zeros (cnt, ptr[abs_size - 1]); exp = src->_mp_exp * FLINT_BITS - cnt; *exp2 = exp; return flint_mpn_get_d (ptr, abs_size, size, (long) - (abs_size * FLINT_BITS - cnt)); } #endif #endif /* Copyright (C) 2016 William Hart This file is part of FLINT. FLINT is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See <https://www.gnu.org/licenses/>. */ #ifndef EXCEPTION_H #define EXCEPTION_H typedef enum { FLINT_ERROR, /* general error */ FLINT_IMPINV, /* impossible inverse */ FLINT_DOMERR, /* domain error */ FLINT_DIVZERO, /* divide by zero */ FLINT_EXPOF, /* exponent overflow */ FLINT_INEXACT /* inexact error */ } flint_err_t; FLINT_DLL FLINT_NORETURN void flint_throw(flint_err_t exc, const char * msg, ...); #endif #ifdef __cplusplus } #endif #endif /* Copyright (C) 2013 Tom Bachmann This file is part of FLINT. FLINT is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See <https://www.gnu.org/licenses/>. */ // This file contains helpers recognising expression templates #ifndef CXX_EXPRESSION_TRAITS_H #define CXX_EXPRESSION_TRAITS_H /* Copyright (C) 2013 Tom Bachmann This file is part of FLINT. FLINT is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See <https://www.gnu.org/licenses/>. */ #ifndef CXX_MP_H #define CXX_MP_H namespace flint { namespace mp { ///////////////////////////////// // BASIC METAPROGRAMMING HELPERS ///////////////////////////////// // Most of these helpers *compute* something. In this case, they have a static // static const member "val" storing the result of the computation. The // arguments of the computation are template parameters, and are usually *not* // PODs, but instead themselves types with a static constant "val" member. // See value_of, true_ and false_ for how to pass in explicit values to your // computation. // Wrap the boolean value "v" into the static const member "val". template<bool v> struct value_of { static const bool val = v; }; // Boolean inputs for computations. struct true_ : value_of<true> { }; struct false_ : value_of<false> { }; // Compute if two input *types* (not values!) are equal. template<class T, class U> struct equal_types : false_ { }; template<class T> struct equal_types<T, T> : true_ { }; // Compute logical negation of the input value. template<class T> struct not_ : value_of<!T::val> { }; // Compute logical and of the input values. template<class T1, class T2, class T3 = void, class T4 = void, class T5 = void, class T6 = void, class T7 = void, class T8 = void> struct and_ : and_<T1, and_<T2, T3, T4, T5, T6, T7, T8> > { }; template<class T, class U> struct and_<T, U, void, void, void, void> : value_of<T::val && U::val> { }; template<class T, bool u> struct and_v : and_<T, value_of<u> > { }; // Compute logical or of the input values. template<class T1, class T2, class T3 = void, class T4 = void, class T5 = void, class T6 = void> struct or_ : or_<T1, or_<T2, T3, T4, T5> > { }; template<class T, class U> struct or_<T, U, void, void, void, void> : value_of<T::val || U::val> { }; // Compute V1 or V2, depending on C template<bool C, class V1, class V2> struct if_v {typedef V1 type;}; template<class V1, class V2> struct if_v<false, V1, V2> {typedef V2 type;}; template<class C, class V1, class V2> struct if_ : if_v<C::val, V1, V2> { }; // Choose a value depending on a sequence of conditions. // This has he same meaning as // int select(bool c1 = false, bool c2 = false, bool c3 = false) // { // if(c1) // return v1; // if(c2) // return v2; // if(c3) // return v3; // return d; // } template<class D, class C1 = void, class V1 = void, class C2 = void, class V2 = void, class C3 = void, class V3 = void> struct select : if_<C1, V1, typename select<D, C2, V2, C3, V3>::type> { }; template<class D> struct select<D, void, void, void, void, void, void> {typedef D type;}; // Conditional template enabling helper. (See below for explanation.) template<bool, class U = void> struct enable_if_v { typedef U type; static const int val = 0; }; template<class U> struct enable_if_v<false, U> { }; // Conditional template enabling. // // These two helpers (enable_if and disable_if) can be used wherever the // SFINAE rule applies to conditionally enable or disable template // specialisations. // // If T evaluaties to true, then enable_if has a member typedef "type", which // is the parameter U, and also a static const int member val (of zero). // If on the other hand T evaluates to false, then enable_if is empty. // The meaning of T is reversed for disable_if. // See e.g. [0] or the tests for how to use this. // // [0] https://www.boost.org/doc/libs/1_53_0/libs/utility/enable_if.html // template<class T, class U = void> struct enable_if : public enable_if_v<T::val, U> { }; template<class T, class U = void> struct disable_if : public enable_if<not_<T>, U> { }; struct empty { }; } // mp } // flint #endif /* Copyright (C) 2013 Tom Bachmann This file is part of FLINT. FLINT is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See <https://www.gnu.org/licenses/>. */ #ifndef CXX_TRAITS_H #define CXX_TRAITS_H // only for true_/false_ namespace flint { namespace detail { template<class T> struct wrap { T t; }; } // detail namespace traits { /////////////////////// // BASIC TYPE TRAITS /////////////////////// // These helpers can be used to manipulate and inquire type information. // For example, given an arbitrary type T, one might be interested in knowing // if it is an integral type (int, short, ulong, etc). // // This file contains generic traits, not specific to FLINT. using mp::true_; using mp::false_; // Compute if T belongs to the signed integer types. template<class T> struct is_signed_integer : false_ { }; template<> struct is_signed_integer<signed char> : true_ { }; template<> struct is_signed_integer<signed short> : true_ { }; template<> struct is_signed_integer<signed int> : true_ { }; template<> struct is_signed_integer<slong> : true_ { }; // Compute if T belongs to the unsigned integer types. template<class T> struct is_unsigned_integer : false_ { }; template<> struct is_unsigned_integer<unsigned char> : true_ { }; template<> struct is_unsigned_integer<unsigned short> : true_ { }; template<> struct is_unsigned_integer<unsigned int> : true_ { }; template<> struct is_unsigned_integer<ulong> : true_ { }; // Compute if T belongs to the signed or unsigned integer types template<class T> struct is_integer : mp::or_<is_unsigned_integer<T>, is_signed_integer<T> > { }; // Compute if T can always losslessly be converted into an slong template<class T, class Enable = void> struct fits_into_slong : mp::false_ { }; template<class T> struct fits_into_slong<T, typename mp::enable_if<traits::is_integer<T> >::type> : mp::or_< is_signed_integer<T>, mp::and_v< is_unsigned_integer<T>, sizeof(T) < sizeof(slong) > > { }; template<class T> struct fits_into_flint_bitcnt_t : is_unsigned_integer<T> { }; // Compute if T is like const char* template<class T> struct is_string : mp::false_ { }; template<> struct is_string<char*> : mp::true_ { }; template<> struct is_string<const char*> : mp::true_ { }; template<int n> struct is_string<char[n]> : mp::true_ { }; template<int n> struct is_string<const char[n]> : mp::true_ { }; // Compute a type appropriate for forwarding T. This is just the appropriate // constant reference type (but avoids things like const (int&)&, which cause // syntax errors. template<class T, class E = void> struct forwarding {typedef const T& type;}; template<class T> struct forwarding<T&> {typedef T& type;}; template<class T> struct forwarding<const T&> {typedef const T& type;}; template<class T> struct forwarding<T, typename mp::enable_if<is_integer<T> >::type> { typedef T type; }; template<class T> struct forwarding<T*> {typedef T* type;}; template<> struct forwarding<bool> {typedef bool type;}; // Compute a type appropriate for referencing. Usually T&. template<class T> struct reference {typedef T& type;}; template<class T> struct reference<T&> {typedef T& type;}; template<class T> struct reference<const T&> {typedef const T& type;}; // Add a constant qualification. In particular, turn T& into const T&. template<class T> struct make_const {typedef const T type;}; template<class T> struct make_const<T&> {typedef const T& type;}; // Strip const and reference type annotations. This does *not* strip pointers! template<class T> struct basetype {typedef T type;}; template<class T> struct basetype<const T> {typedef T type;}; template<class T> struct basetype<T&> {typedef T type;}; template<class T> struct basetype<const T&> {typedef T type;}; struct no { int data[2]; }; typedef int yes; template<class T> detail::wrap<T> fakeinstance(); // use with care template<class To, class From> struct _is_convertible { private: static yes test(...) {return yes();} static no test(To) {return no();} public: static const bool val = (sizeof(test(fakeinstance<From>().t)) != sizeof(yes)); }; // XXX HACK template<class To, class A, class B> struct _is_convertible<To, A(B)> : false_ { }; } // traits } // flint #endif namespace flint { namespace operations { // These are the operation tags the expression class creates directly. // unary operations struct immediate { }; struct negate { }; struct complement { }; // binary operations struct plus { }; struct minus { }; struct times { }; struct divided_by { }; struct modulo { }; struct shift { }; // left struct binary_and { }; struct binary_or { }; struct binary_xor { }; } // operations namespace traits { template<class T, class Enable = void> struct is_expression : mp::false_ { }; template<class T> struct is_expression<T, typename T::IS_EXPRESSION_MARKER> : mp::true_ { }; template<class T> struct _is_immediate_expr : _is_convertible< typename basetype<T>::type::operation_t, operations::immediate > { }; // Compute if T is an expression, with operation "immediate" template<class T, class Enable = void> struct is_immediate_expr : _is_immediate_expr<T> { }; template<class T> struct is_immediate_expr<T, typename mp::enable_if<mp::not_<is_expression<T> > >::type> : mp::false_ { }; // Compute if T is an immediate expression, *or not an expression at all* template<class T> struct is_immediate : mp::or_<mp::not_<is_expression<T> >, is_immediate_expr<T> > { }; // Compute if T is a non-immediate expression template<class T> struct is_lazy_expr : mp::and_<is_expression<T>, mp::not_<is_immediate_expr<T> > > { }; // Compute if Expr is an expression with prescribed evaluated type "T" template<class Expr, class T, class Enable = void> struct is_T_expr : mp::equal_types<typename Expr::evaluated_t, T> { }; template<class Expr, class T> struct is_T_expr<Expr, T, typename mp::disable_if<traits::is_expression<Expr> >::type> : false_ { }; // Decide if an expressing yielding From can be directly evaluated into To. // To be further specialised! template<class To, class From, class Enable = void> struct can_evaluate_into : mp::false_ { }; template<class T> struct can_evaluate_into<T, T> : mp::true_ { }; // Decide if we should use temporary merging template<class Expr> struct use_temporary_merging : mp::true_ { }; } // traits } // flint #endif /* Copyright (C) 2013 Tom Bachmann This file is part of FLINT. FLINT is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See <https://www.gnu.org/licenses/>. */ // This file contains the definitions of all rules used by the expression class. // (Some generally useful implementations can be found in default_rules.h.) // This file also contains some helper traits, metaprogramming tools and macros. #ifndef CXX_RULES_H #define CXX_RULES_H namespace flint { namespace rules { struct no_op { template<class U> static void doit(const U&) {} }; struct UNIMPLEMENTED { static const bool unimplemented_marker = true; }; template<class T, class Enable = void> struct print : UNIMPLEMENTED { }; template<class T, class Enable = void> struct to_string : UNIMPLEMENTED { }; // static std::string get(const T&, int base) template<class T, class U, class Enable = void> struct assignment : UNIMPLEMENTED { }; // C-style cmp. template<class T, class U, class Enable = void> struct cmp : UNIMPLEMENTED { }; // Rule for equals. Implemented in terms of cmp by default. template<class T, class U, class Enable = void> struct equals : UNIMPLEMENTED { }; // Rule for type conversion. template<class To, class From, class Enable = void> struct conversion { static To get(const From& from) { return To(from); } }; // Rule for c-style printing template<class T, class Enable = void> struct cprint : UNIMPLEMENTED { }; // static int doit(FILE*, const T&) template<class T, class Enable = void> struct print_pretty : UNIMPLEMENTED { }; // static int doit(FILE*, const T&) template<class T, class Enable = void> struct read : UNIMPLEMENTED { }; // static int doit(FILE*, T&) // Rule for swapping template<class To, class From, class Enable = void> struct swap : UNIMPLEMENTED { }; // If result_is_temporary is true, then the result coincides with the // first temporary (provided these have the same type) // Priorities 2, 1, 0 can be used to resolve conflicts. template< class Op, class Data, bool result_is_temporary, unsigned priority, class Enable = void> struct evaluation : UNIMPLEMENTED { }; //{ // typedef X return_t; // typedef Y temporaries_t; // a tuple of *pointers* // static void doit(const T& input, temporaries_t temps, return_t* output); //}; // Instantiate temporaries for evaluation. The default implementation does the // following: // - find a subexpression t of e which evaluates to type T // -- return t.create_temporary() // - if no such subexpression can be found, return T() // Additionally, the expression class implements a version of create_temporary // which just returns T(), so if your class is default constructible, // everything works automatically. template<class Expr, class T, class Enable = void> struct instantiate_temporaries; //{ // static T get(const Expr& e); //}; // Convenience helpers, instantiate by evaluation if necessary // (needs default rules) template<class T, class Op, class U, class Enable = void> struct binary_expression : UNIMPLEMENTED { }; // typedef X return_t; // static void doit(return_t& to, const T&, const U&); template<class T, class Op, class U, class Enable = void> struct commutative_binary_expression : UNIMPLEMENTED { }; // similarly template<class Op, class T, class Enable = void> struct unary_expression : UNIMPLEMENTED { }; // similarly // Rules for more arguments. template<class Op, class T, class U, class V, class Enable = void> struct threeary_expression : UNIMPLEMENTED { }; template<class Op, class T, class U, class V, class W, class Enable = void> struct fourary_expression : UNIMPLEMENTED { }; template<class Op, class T, class U, class V, class W, class X, class Enable = void> struct fiveary_expression : UNIMPLEMENTED { }; template<class Op, class T, class U, class V, class W, class X, class Y, class Enable = void> struct sixary_expression : UNIMPLEMENTED { }; template<class Op, class T, class U, class V, class W, class X, class Y, class Z, class Enable = void> struct sevenary_expression : UNIMPLEMENTED { }; } // rules /////////////////////////////////////////////////////////////////////////////////// // HELPER TRAITS /////////////////////////////////////////////////////////////////////////////////// namespace traits { // Compute if the rule T is implemented. template<class T> struct is_implemented : mp::not_<_is_convertible<rules::UNIMPLEMENTED, T> > { }; } // traits } // flint /////////////////////////////////////////////////////////////////////////////////// // HELPER MACROS /////////////////////////////////////////////////////////////////////////////////// // These macros should be called in namespace flint::rules // In general the easiest way to find out what they do is to read the // definition directly. // Specialise a getter called "name". The getter has one argument called "from" // of type "fromtype", and "eval" which should yield "totype". #define FLINT_DEFINE_GET2(name, totype, fromtype1, fromtype2, eval) \ template<> \ struct name<fromtype1, fromtype2> \ { \ static totype get(const fromtype1& e1, const fromtype2& e2) \ { \ return eval; \ } \ }; #define FLINT_DEFINE_GET(name, totype, fromtype, eval) \ FLINT_DEFINE_GET2(name, totype, fromtype, fromtype, eval) #define FLINT_DEFINE_GET_COND(name, totype, cond, eval) \ template<class T> \ struct name<totype, T, typename mp::enable_if< cond<T> >::type> \ { \ static totype get(const T& from) \ { \ return eval; \ } \ }; // Specialise a doit rule called "name" #define FLINT_DEFINE_DOIT(name, totype, fromtype, eval) \ template<> \ struct name<totype, fromtype> \ { \ static void doit(totype& to, const fromtype& from) \ { \ eval; \ } \ }; // Specialise a doit rule called "name" which yields totype. It will // accept any type "T" which satisfies "cond". #define FLINT_DEFINE_DOIT_COND(name, totype, cond, eval) \ template<class T> \ struct name<totype, T, typename mp::enable_if< cond<T> >::type> \ { \ static void doit(totype& to, const T& from) \ { \ eval; \ } \ }; #define FLINT_DEFINE_DOIT_COND2(name, cond1, cond2, eval) \ template<class T, class U> \ struct name<T, U, typename mp::enable_if<mp::and_< cond1 <T>, cond2 <U> > >::type> \ { \ static void doit(T& to, const U& from) \ { \ eval; \ } \ }; #define FLINT_DEFINE_PRINT_COND_(name, cond, eval) \ template<class T> \ struct name<T, typename mp::enable_if< cond <T> >::type> \ { \ static int doit(FILE* to, const T& from) \ { \ return eval; \ } \ }; #define FLINT_DEFINE_READ_COND_(name, cond, eval) \ template<class T> \ struct name<T, typename mp::enable_if< cond <T> >::type> \ { \ static int doit(FILE* from, T& to) \ { \ return eval; \ } \ }; #define FLINT_DEFINE_PRINT_COND(cond, eval) \ FLINT_DEFINE_PRINT_COND_(cprint, cond, eval) #define FLINT_DEFINE_PRINT_PRETTY_COND(cond, eval) \ FLINT_DEFINE_PRINT_COND_(print_pretty, cond, eval) #define FLINT_DEFINE_READ_COND(cond, eval) \ FLINT_DEFINE_READ_COND_(read, cond, eval) #define FLINT_DEFINE_PRINT_PRETTY_COND_2(cond, extratype, eval) \ template<class T> \ struct print_pretty<T, typename mp::enable_if< cond <T> >::type> \ { \ static int doit(FILE* to, const T& from, extratype extra) \ { \ return eval; \ } \ }; // Specialise the unary expression rule type->type. #define FLINT_DEFINE_UNARY_EXPR_(name, rtype, type, eval) \ template<> \ struct unary_expression<operations::name, type> \ { \ typedef rtype return_t; \ template<class V> \ static void doit(V& to, const type& from) \ { \ eval; \ } \ }; #define FLINT_DEFINE_UNARY_EXPR(name, type, eval) \ FLINT_DEFINE_UNARY_EXPR_(name, type, type, eval) #define FLINT_DEFINE_UNARY_EXPR_COND(name, ret_type, cond, eval) \ template<class T> \ struct unary_expression<operations::name, T, \ typename mp::enable_if<cond<T> >::type> \ { \ typedef ret_type return_t; \ template<class V> \ static void doit(V& to, const T& from) \ { \ eval; \ } \ }; // Specialise the binary expression rule (type, type) -> type #define FLINT_DEFINE_BINARY_EXPR2(name, rtype, type1, type2, eval) \ template<> \ struct binary_expression<type1, operations::name, type2> \ { \ typedef rtype return_t; \ template<class V> \ static void doit(V& to, const type1& e1, const type2& e2) \ { \ eval; \ } \ }; #define FLINT_DEFINE_BINARY_EXPR(name, type, eval) \ FLINT_DEFINE_BINARY_EXPR2(name, type, type, type, eval) // Specialise the commutative binary expression rule (type, type) -> type #define FLINT_DEFINE_CBINARY_EXPR(name, type, eval) \ template<> \ struct commutative_binary_expression<type, operations::name, type> \ { \ typedef type return_t; \ template<class V> \ static void doit(V& to, const type& e1, const type& e2) \ { \ eval; \ } \ }; // Specialise the commutative binary expression rule (Type, T) -> Type, // where T must satisfy "cond". #define FLINT_DEFINE_CBINARY_EXPR_COND(name, Type, cond, eval) \ template<class T> \ struct commutative_binary_expression<Type, operations::name, T, \ typename mp::enable_if<cond<T> >::type> \ { \ typedef Type return_t; \ template<class V> \ static void doit(V& to, const Type& e1, const T& e2) \ { \ eval; \ } \ }; #define FLINT_DEFINE_CBINARY_EXPR_COND2(name, rettype, cond1, cond2, eval) \ template<class T, class U> \ struct commutative_binary_expression<T, operations::name, U, \ typename mp::enable_if<mp::and_< cond1 <T>, cond2 <U> > >::type> \ { \ typedef rettype return_t; \ template<class V> \ static void doit(V& to, const T& e1, const U& e2) \ { \ eval; \ } \ }; // Specialise the (non-commutative) binary expression rule (Type, T) -> Type, // where T must satisfy "cond". #define FLINT_DEFINE_BINARY_EXPR_COND(name, Type, cond, eval) \ template<class T> \ struct binary_expression<Type, operations::name, T, \ typename mp::enable_if<cond<T> >::type> \ { \ typedef Type return_t; \ template<class V> \ static void doit(V& to, const Type& e1, const T& e2) \ { \ eval; \ } \ }; #define FLINT_DEFINE_BINARY_EXPR_COND2(name, rettype, cond1, cond2, eval) \ template<class T, class U> \ struct binary_expression<T, operations::name, U, \ typename mp::enable_if< mp::and_< cond1 <T>, cond2 <U> > >::type> \ { \ typedef rettype return_t; \ template<class V> \ static void doit(V& to, const T& e1, const U& e2) \ { \ eval; \ } \ }; #define FLINT_DEFINE_THREEARY_EXPR_COND3(name, rettype, cond1, cond2, cond3, eval) \ template<class T, class U, class V> \ struct threeary_expression<operations::name, T, U, V, \ typename mp::enable_if< mp::and_< cond1 <T>, cond2 <U>, cond3 <V> > >::type> \ { \ typedef rettype return_t; \ template<class R> \ static void doit(R& to, const T& e1, const U& e2, const V& e3) \ { \ eval; \ } \ }; #define FLINT_DEFINE_THREEARY_EXPR(name, rettype, T1, T2, T3, eval) \ template<> \ struct threeary_expression<operations::name, T1, T2, T3> \ { \ typedef rettype return_t; \ template<class R> \ static void doit(R& to, const T1& e1, const T2& e2, const T3& e3) \ { \ eval; \ } \ }; #define FLINT_DEFINE_FOURARY_EXPR_COND4(name, rettype, cond1, cond2, cond3, cond4, eval) \ template<class T, class U, class V, class W> \ struct fourary_expression<operations::name, T, U, V, W, \ typename mp::enable_if< mp::and_< cond1 <T>, cond2 <U>, cond3 <V>, cond4 <W> > >::type> \ { \ typedef rettype return_t; \ template<class R> \ static void doit(R& to, const T& e1, const U& e2, const V& e3, const W& e4) \ { \ eval; \ } \ }; #define FLINT_DEFINE_FIVEARY_EXPR_COND5(name, rettype, cond1, cond2, cond3, cond4, cond5, eval) \ template<class T, class U, class V, class W, class X> \ struct fiveary_expression<operations::name, T, U, V, W, X, \ typename mp::enable_if< mp::and_< cond1 <T>, cond2 <U>, cond3 <V>, cond4 <W>, cond5 <X> > >::type> \ { \ typedef rettype return_t; \ template<class R> \ static void doit(R& to, const T& e1, const U& e2, const V& e3, const W& e4, const X& e5) \ { \ eval; \ } \ }; #define FLINT_DEFINE_SIXARY_EXPR_COND6(name, rettype, cond1, cond2, cond3, cond4, cond5, cond6, eval) \ template<class T, class U, class V, class W, class X, class Y> \ struct sixary_expression<operations::name, T, U, V, W, X, Y, \ typename mp::enable_if< mp::and_< cond1 <T>, cond2 <U>, cond3 <V>, cond4 <W>, cond5 <X>, cond6<Y> > >::type> \ { \ typedef rettype return_t; \ template<class R> \ static void doit(R& to, const T& e1, const U& e2, const V& e3, const W& e4, const X& e5, const Y& e6) \ { \ eval; \ } \ }; #define FLINT_DEFINE_SEVENARY_EXPR_COND7(name, rettype, cond1, cond2, cond3, cond4, cond5, cond6, cond7, eval) \ template<class T, class U, class V, class W, class X, class Y, class Z> \ struct sevenary_expression<operations::name, T, U, V, W, X, Y, Z, \ typename mp::enable_if< mp::and_< cond1 <T>, cond2 <U>, cond3 <V>, cond4 <W>, cond5 <X>, cond6<Y>, cond7<Z> > >::type> \ { \ typedef rettype return_t; \ template<class R> \ static void doit(R& to, const T& e1, const U& e2, const V& e3, const W& e4, const X& e5, const Y& e6, const Z& e7) \ { \ eval; \ } \ }; #endif /* Copyright (C) 2013 Tom Bachmann This file is part of FLINT. FLINT is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See <https://www.gnu.org/licenses/>. */ #ifndef CXX_TUPLE_H #define CXX_TUPLE_H namespace flint { /////////////////////////// // A general tuple class. /////////////////////////// // This simply stores a head and a tail. Conventionally, tuples a built by // nesting the tail. The last entry should be an empty_tuple (see below). // So e.g. a pair of integers would be tuple<int, tuple<int, empty_tuple> >. // // There are some helpers in the mp namespace below. namespace detail { struct FILLIT { }; } // detail namespace mp { namespace htuples { // Filling of tuples template<class Tuple, class Filler> Tuple fill(const Filler& f) { return Tuple(detail::FILLIT(), f); } } // htuples } // mp template<class Head, class Tail> struct tuple { Head head; Tail tail; typedef Head head_t; typedef Tail tail_t; static const unsigned len = 1 + Tail::len; // Obtain a reference to head (convenience name for pairs). typename traits::reference<head_t>::type first() {return head;} typename traits::forwarding<head_t>::type first() const {return head;} // Obtain a reference to the head of the tail (convenience name for pairs). typename traits::reference<typename Tail::head_t>::type second() {return tail.head;} typename traits::forwarding<typename Tail::head_t>::type second() const {return tail.head;} tuple() {}; tuple(typename traits::forwarding<Head>::type h, typename traits::forwarding<Tail>::type t) : head(h), tail(t) { } bool operator==(const tuple& other) { return head == other.head && tail == other.tail; } template<class T> void set(const T& t) { head = t.head; tail.set(t.tail); } template<class T> void set(T& t) { head = t.head; tail.set(t.tail); } template<class T> bool equals_elementwise(const T& t) const { return head == t.head && tail.equals_elementwise(t.tail); } private: template<class Filler> tuple(detail::FILLIT fillit, const Filler& f) : head(f.template create<head_t>()), tail(fillit, f) { } template<class Tuple, class Filler> friend Tuple mp::htuples::fill(const Filler&); template<class H, class T> friend struct tuple; }; struct empty_tuple { struct empty { }; typedef empty head_t; typedef empty tail_t; empty head; empty tail; static const unsigned len = 0; bool operator==(const empty_tuple&) {return true;} empty_tuple() {} void set(empty_tuple) {} bool equals_elementwise(empty_tuple) const {return true;} private: template<class Filler> empty_tuple(detail::FILLIT fillit, const Filler& f) { } template<class Tuple, class Filler> friend Tuple mp::htuples::fill(const Filler&); template<class Head, class Tail> friend struct tuple; }; namespace detail { typedef void UNUSED; template<class T> struct maybe_forwarding { typedef typename traits::forwarding<T>::type type; static type default_value(); }; template<> struct maybe_forwarding<UNUSED> { typedef UNUSED* type; static type default_value() {return 0;} }; } namespace mp { // Helper to conveniently define tuple types, and marshall objects into // tuples. // Typical usage: // typedef make_tuple<int, char, slong> maker; // maker::type my_tuple = maker::make(1, 'a', WORD(2)); // TODO this would be a prime use for variadic templates ... #define FLINTXX_MAKE_TUPLE_TEMPLATE_ARGS \ class T1 = detail::UNUSED, class T2 = detail::UNUSED, \ class T3 = detail::UNUSED, class T4 = detail::UNUSED, \ class T5 = detail::UNUSED, class T6 = detail::UNUSED, \ class T7 = detail::UNUSED, class T8 = detail::UNUSED #define FLINTXX_MAKE_TUPLE_FUNC_ARGS \ typename detail::maybe_forwarding<T1>::type t1 \ = detail::maybe_forwarding<T1>::default_value(), \ typename detail::maybe_forwarding<T2>::type t2 \ = detail::maybe_forwarding<T2>::default_value(), \ typename detail::maybe_forwarding<T3>::type t3 \ = detail::maybe_forwarding<T3>::default_value(), \ typename detail::maybe_forwarding<T4>::type t4 \ = detail::maybe_forwarding<T4>::default_value(), \ typename detail::maybe_forwarding<T5>::type t5 \ = detail::maybe_forwarding<T5>::default_value(), \ typename detail::maybe_forwarding<T6>::type t6 \ = detail::maybe_forwarding<T6>::default_value(), \ typename detail::maybe_forwarding<T7>::type t7 \ = detail::maybe_forwarding<T7>::default_value(), \ typename detail::maybe_forwarding<T8>::type t8 \ = detail::maybe_forwarding<T8>::default_value() #define FLINTXX_MAKE_TUPLE_TYPES_APPLYMACRO(func) \ func(T1), func(T2), func(T3), func(T4), \ func(T5), func(T6), func(T7), func(T8) #define FLINTXX_MAKE_TUPLE_FUNC_ARG_NAMES t1, t2, t3, t4, t5, t6, t7, t8 template<FLINTXX_MAKE_TUPLE_TEMPLATE_ARGS> struct make_tuple { typedef make_tuple<T2, T3, T4, T5, T6, T7, T8> next; typedef typename next::type tail_t; typedef tuple<T1, tail_t> type; static type make(FLINTXX_MAKE_TUPLE_FUNC_ARGS) { return type(t1, next::make(t2, t3, t4, t5, t6, t7, t8)); } }; template<> struct make_tuple<detail::UNUSED, detail::UNUSED, detail::UNUSED, detail::UNUSED, detail::UNUSED, detail::UNUSED, detail::UNUSED, detail::UNUSED> { typedef detail::UNUSED* T; typedef empty_tuple type; // g++-4.4 bolts if we use (...), even though all arguments are PODs static empty_tuple make(T=0, T=0, T=0, T=0, T=0, T=0, T=0, T=0) {return empty_tuple();} }; // Indexified access template<class Tuple, unsigned idx> struct tuple_get { typedef tuple_get<typename Tuple::tail_t, idx-1> nget; typedef typename nget::type type; static typename traits::forwarding<type>::type get(const Tuple& t) { return nget::get(t.tail); } static typename traits::reference<type>::type get(Tuple& t) { return nget::get(t.tail); } }; template<class Tuple> struct tuple_get<Tuple, 0> { typedef typename Tuple::head_t type; static typename traits::forwarding<type>::type get(const Tuple& t) { return t.head; } static typename traits::reference<type>::type get(Tuple& t) { return t.head; } }; // Create a tuple backing a tuple of points. // That is to say, given a tuple like <A*, B*, C*, D*>, // compute a backing tuple type <A, B, C, D>. // // If one of the types in the tuple is Return*, do not back it // and instead feed it in separately. I.e. if Return is A*, then type // will be just <B*, C*, D*>. // // The static member init(to, from, ret) can be used to initialize the tuple // of pointers "to" to point to its backing in "from" and "ret". template<class Tuple, class Return = void> struct back_tuple; // General case: non-empty tuple <Head, Tail>, and Return type cannot be // merged in. template<class Head, class Tail, class Return> struct back_tuple<tuple<Head*, Tail>, Return> { typedef tuple<Head, typename back_tuple<Tail, Return>::type> type; static void init(tuple<Head*, Tail>& to, type& from, Return* ret = 0) { back_tuple<Tail, Return>::init(to.tail, from.tail, ret); to.head = &from.head; } }; // Merging case: non-empty tuple <Head, Tail>, and Return is Head* template<class Head, class Tail> struct back_tuple<tuple<Head*, Tail>, Head> { typedef typename back_tuple<Tail, void /* no more merging */>::type type; static void init(tuple<Head*, Tail>& to, type& from, Head* ret = 0) { to.head = ret; back_tuple<Tail, void>::init(to.tail, from, 0 /* unused */ ); } }; // Base case: empty tuple; nothing to do. template<class Return> struct back_tuple<empty_tuple, Return> { typedef empty_tuple type; static void init(empty_tuple& to, type& from, Return* ret = 0) { } }; // Helper to concatenate two tuples. // // This has one member type, and three static member functions get_second, // get_first and doit. // "type" is a tuple type which can store the data of both Tuple1 and Tuple2. // Then, given an element of type "type", get_first and get_second can be used // to fill types Tuple1 and Tuple2. Note that get_second can return a constant // reference, whereas get_first has to do copying. // (But these copies should usually be inlined and optimized away by the // compiler.) // // Example: Tuple1 = <A, B, C>, Tuple2 = <D, E>. // Then type = <A, B, C, D, E> // get_second(t) = t.tail.tail.tail // get_first(t) = tuple(t.head, tuple(t.tail.head, tuple( // t.tail.tail.head, empty_tuple()))); // template<class Tuple1, class Tuple2> struct concat_tuple; // Degenerate case: Tuple1 is empty. template<class Tuple2> struct concat_tuple<empty_tuple, Tuple2> { typedef Tuple2 type; static const Tuple2& get_second(const Tuple2& t) {return t;} static empty_tuple get_first(const Tuple2& t) {return empty_tuple();} static type doit(const empty_tuple& t1, const Tuple2& t2) {return t2;} }; // General case: non-empty Tuple1. template<class Head, class Tail, class Tuple2> struct concat_tuple<tuple<Head, Tail>, Tuple2> { typedef tuple<Head, typename concat_tuple<Tail, Tuple2>::type> type; static const Tuple2& get_second(const type& t) { return concat_tuple<Tail, Tuple2>::get_second(t.tail); } static tuple<Head, Tail> get_first(const type& o) { return tuple<Head, Tail>( o.head, concat_tuple<Tail, Tuple2>::get_first(o.tail)); } static type doit(const tuple<Head, Tail>& t1, const Tuple2& t2) { return type(t1.head, concat_tuple<Tail, Tuple2>::doit(t1.tail, t2)); } }; // Merging of tuples // // This takes two tuples, and computes a tuple type which can store either. // As usual, the extraction functions require copying which can be amortized // by the compiler. // template<class Tuple1, class Tuple2> struct merge_tuple; //{ // typedef XYZ type; // Tuple1 get_first(const type& type); // Tuple2 get_second(const type& type); //}; // General case // NB: tail is *always* a sub-tuple of the second argument! template<class Head, class Tail, class Tuple2> struct merge_tuple<tuple<Head, Tail>, Tuple2> { public: typedef merge_tuple<Tail, Tuple2> comp1; typedef merge_tuple<tuple<Head, empty_tuple>, typename comp1::tail_t> comp2; typedef concat_tuple<typename comp1::used_t, typename comp2::type> concater; public: typedef typename concater::type type; // This is the part of type into which we can still merge. typedef typename comp2::tail_t tail_t; typedef typename concat_tuple< typename comp1::used_t, typename comp2::used_t >::type used_t; private: static typename comp1::type get_tail(const type& input) { typedef concat_tuple< typename comp1::used_t, typename comp1::tail_t > myconcat; return myconcat::doit(concater::get_first(input), comp2::get_second(concater::get_second(input))); } public: static tuple<Head, Tail> get_first(const type& input) { Head h = comp2::get_first(concater::get_second(input)).first(); return tuple<Head, Tail>(h, comp1::get_first(get_tail(input))); } static Tuple2 get_second(const type& input) { return comp1::get_second(get_tail(input)); } }; // First argument a singleton, no merging template<class T, class U, class Tail> struct merge_tuple<tuple<T, empty_tuple>, tuple<U, Tail> > { private: typedef merge_tuple<tuple<T, empty_tuple>, Tail> comp; typedef concat_tuple< typename comp::used_t, tuple<U, typename comp::tail_t> > concater; public: typedef typename comp::used_t used_t; typedef tuple<U, typename comp::tail_t> tail_t; typedef typename concater::type type; private: static typename comp::type get_tail(const type& input) { typedef concat_tuple< typename comp::used_t, typename comp::tail_t > myconcat; return myconcat::doit(concater::get_first(input), concater::get_second(input).tail); } public: static tuple<T, empty_tuple> get_first(const type& input) { return comp::get_first(get_tail(input)); } static tuple<U, Tail> get_second(const type& input) { return tuple<U, Tail>( concater::get_second(input).head, comp::get_second(get_tail(input))); } }; // First argument a singleton, with merging template<class T, class Tail> struct merge_tuple<tuple<T, empty_tuple>, tuple<T, Tail> > { typedef tuple<T, Tail> type; typedef tuple<T, empty_tuple> used_t; typedef Tail tail_t; static tuple<T, empty_tuple> get_first(const type& input) { return make_tuple<T>::make(input.head); } static tuple<T, Tail> get_second(const type& input) { return input; } }; // Termination case 1 template<class Tuple2> struct merge_tuple<empty_tuple, Tuple2> { typedef Tuple2 type; typedef type tail_t; typedef empty_tuple used_t; static empty_tuple get_first(const type& input) { return empty_tuple(); } static Tuple2 get_second(const type& input) { return input; } }; // It seems like this code path is unnecessary and in fact ambiguous. // I am fairly convinced by now this is correct. // However, in case issues ever come up, it seemed useful to me to retain this. // -- Tom Bachmann (15/10/2013) #if 0 // Termination case 2 template<class Tuple1> struct merge_tuple<Tuple1, empty_tuple> { typedef Tuple1 type; typedef type tail_t; typedef empty_tuple used_t; static Tuple1 get_first(const type& input) { return input; } static empty_tuple get_second(const type& input) { return empty_tuple(); } }; #endif // Termination case 3 template<class T> struct merge_tuple<tuple<T, empty_tuple>, empty_tuple> { typedef tuple<T, empty_tuple> type; typedef empty_tuple tail_t; // NB: we "use" T here - it cannot be merged into it any longer! typedef type used_t; static empty_tuple get_second(const type& input) { return empty_tuple(); } static tuple<T, empty_tuple> get_first(const type& input) { return input; } }; // Termination case 4 template<> struct merge_tuple<empty_tuple, empty_tuple> { typedef empty_tuple type; typedef empty_tuple tail_t; typedef empty_tuple used_t; static empty_tuple get_first(const type& input) {return empty_tuple();} static empty_tuple get_second(const type& input) {return empty_tuple();} }; // Creation and manipulation of homogeneous tuples // Build a tuple type of "n" repetitions of "T". template<class T, unsigned n> struct make_homogeneous_tuple { typedef tuple<T, typename make_homogeneous_tuple<T, n-1>::type> type; }; template<class T> struct make_homogeneous_tuple<T, 0> { typedef empty_tuple type; }; namespace htuples { namespace hdetail { template<unsigned n, class Tuple> struct extract_helper { typedef typename Tuple::head_t T; typedef typename Tuple::tail_t tail_t; typedef typename make_homogeneous_tuple<T, n>::type ht; static ht get_noskip(const Tuple& tuple) { return ht(tuple.head, extract_helper<n-1, tail_t>::get_noskip( tuple.tail)); } }; template<class Tuple> struct extract_helper<0, Tuple> { static empty_tuple get_noskip(const Tuple&) {return empty_tuple();} }; template<class Tuple> struct remove_helper { static const unsigned n = Tuple::len; typedef typename Tuple::tail_t tail_t; typedef typename Tuple::head_t T; static tail_t get(const Tuple& tuple, T res) { if(tuple.head == res) return tuple.tail; return tail_t(tuple.head, remove_helper<tail_t>::get(tuple.tail, res)); } }; template<class T> struct remove_helper<tuple<T, empty_tuple> > { static empty_tuple get(const tuple<T, empty_tuple>&, T) { return empty_tuple(); } }; } // hdetail // Extract the first "n" values from the *homogeneous* tuple "tuple". template<unsigned n, class Tuple> inline typename make_homogeneous_tuple<typename Tuple::head_t, n>::type extract( const Tuple& tuple) { return hdetail::extract_helper<n, Tuple>::get_noskip(tuple); } // Remove one element from the *homogeneous* tuple "tuple", if possible "res". // Example: // t1 = (1, 2, 3, 4) // t2 = (1, 1, 1, 1) // t3 = (2, 3, 4, 5) // // removeres(t1, 1) -> (2, 3, 4) // removeres(t2, 1) -> (1, 1, 1) // removeres(t3, 1) -> (2, 3, 4) or any other three element subset template<class Tuple> inline typename Tuple::tail_t removeres(const Tuple& tuple, typename Tuple::head_t res) { return hdetail::remove_helper<Tuple>::get(tuple, res); } } // htuples } // mp namespace traits { // Compute if "Tuple" is of the form (U, U, .. U), or empty. template<class Tuple, class U> struct is_homogeneous_tuple : mp::and_< is_homogeneous_tuple<typename Tuple::tail_t, U>, mp::equal_types<typename Tuple::head_t, U> > { }; template<class U> struct is_homogeneous_tuple<empty_tuple, U> : true_ { }; // Compute if T is a tuple template<class T> struct is_tuple : false_ { }; template<class Head, class Tail> struct is_tuple<tuple<Head, Tail> > : true_ { }; template<> struct is_tuple<empty_tuple> : true_ { }; } } // flint #endif namespace flint { namespace mp { // Find the highest-priority implemented evaluation rule, if any. // TODO move to tools? template<class Op, class Data, bool result_is_temporary, unsigned min_prio = 0> struct find_evaluation { private: typedef rules::evaluation<Op, Data, result_is_temporary, 2> r2; typedef rules::evaluation<Op, Data, result_is_temporary, 1> r1; typedef rules::evaluation<Op, Data, result_is_temporary, 0> r0; typedef traits::is_implemented<r2> i2; typedef traits::is_implemented<r1> i1; typedef traits::is_implemented<r0> i0; public: typedef typename mp::select<rules::UNIMPLEMENTED, // TODO mp::and_v<i2, min_prio <= 2>, r2, mp::and_v<i1, min_prio <= 1>, r1, mp::and_v<i0, min_prio <= 0>, r0 >::type type; }; } // mp namespace tools { namespace tdetail { template<class T, class U> struct cmp_invert { static int get(const T& t, const U& u) { return -rules::cmp<U, T>::get(u, t); } }; } // A version of the cmp rule which tries both argument orders template<class T, class U> struct symmetric_cmp : mp::if_<traits::is_implemented<rules::cmp<T, U> >, rules::cmp<T, U>, typename mp::if_<traits::is_implemented<rules::cmp<U, T> >, tdetail::cmp_invert<T, U>, rules::UNIMPLEMENTED >::type >::type { }; // A version of equals which uses cmp if possible namespace tdetail { template<class T, class U, class Enable = void> struct equals_using_cmp_ : rules::UNIMPLEMENTED { }; template<class T, class U> struct equals_using_cmp_<T, U, typename mp::enable_if< traits::is_implemented<symmetric_cmp<T, U> > >::type> { static bool get(const T& t, const U& u) { return tools::symmetric_cmp<T, U>::get(t, u) == 0; } }; } // tdetail template<class T, class U> struct equals_using_cmp : mp::if_<traits::is_implemented<rules::equals<T, U> >, rules::equals<T, U>, tdetail::equals_using_cmp_<T, U> >::type { }; // Automatic printing if to_string is implemented namespace tdetail { template<class T, class Enable = void> struct print_using_str_ : rules::UNIMPLEMENTED { }; template<class T> struct print_using_str_<T, typename mp::enable_if<traits::is_implemented<rules::to_string<T> > >::type> { static void doit(const T& v, std::ostream& o) { int base = 10; std::ios_base::fmtflags ff = o.flags(); if(ff & o.hex) base = 16; if(ff & o.oct) base = 8; o << v.to_string(base); } }; } // tdetail template<class T> struct print_using_str : mp::if_<traits::is_implemented<rules::print<T> >, rules::print<T>, tdetail::print_using_str_<T> >::type { }; // Finding a subexpression of precsribed type namespace tdetail { template<class Pred, class Data, class Enable = void> struct find_subexpr_helper2; template<class Pred, class Expr, class Enable = void> struct find_subexpr_helper { typedef find_subexpr_helper2<Pred, typename Expr::data_t> fsh; typedef typename fsh::rtype rtype; static const bool val = fsh::val; static rtype get(const Expr& e) {return fsh::get(e._data());} }; template<class Pred, class Expr> struct find_subexpr_helper<Pred, Expr, typename mp::enable_if<typename Pred::template type<Expr> >::type> { static const bool val = true; typedef const Expr& rtype; static rtype get(rtype t) {return t;} }; template<class Pred, class Expr> struct find_subexpr_helper<Pred, Expr, typename mp::enable_if<mp::and_<traits::is_immediate<Expr>, mp::not_<typename Pred::template type<Expr> > > >::type> { static const bool val = false; typedef void rtype; }; template<class Pred, class Data, class Enable> struct find_subexpr_helper2 { typedef find_subexpr_helper2<Pred, typename Data::tail_t> fsh; typedef typename fsh::rtype rtype; static const bool val = fsh::val; static rtype get(const Data& d) {return fsh::get(d.tail);} }; template<class Pred, class Head, class Tail> struct find_subexpr_helper2<Pred, tuple<Head, Tail>, typename mp::enable_if<find_subexpr_helper<Pred, typename traits::basetype<Head>::type> >::type> { static const bool val = true; typedef typename traits::basetype<Head>::type head_t; typedef find_subexpr_helper<Pred, head_t> fsh; typedef typename fsh::rtype rtype; static rtype get(const tuple<Head, Tail>& d) {return fsh::get(d.head);} }; template<class Pred> struct find_subexpr_helper2<Pred, empty_tuple> { static const bool val = false; typedef void rtype; }; } // tdetail // A predicate which applies if the argument type equals T. template<class T> struct equal_types_pred { template<class U> struct type : mp::equal_types<T, U> { }; }; // Given an expression template Expr, traverse the tree of data arguments // until an argument matching the predicate Pred is found. Here pred must have // a member template "type" performing the boolean computation. // See equal_types_pred for an example. // If there is no matching subexpression, a compile time error will be // encountered. // The current implementation performs depth-first search. template<class Pred, class Expr> inline typename tdetail::find_subexpr_helper<Pred, Expr>::rtype find_subexpr(const Expr& e) { return tdetail::find_subexpr_helper<Pred, Expr>::get(e); } // Find a subexpression of type T. template<class T, class Expr> inline const T& find_subexpr_T(const Expr& e) { return find_subexpr<equal_types_pred<T> >(e); } // Boolean computation to determine if find_subexpr above will work. template<class Pred, class Expr> struct has_subexpr : tdetail::find_subexpr_helper<Pred, Expr> { }; // A helper to invoke htuples::fill with instantiate_temporaries namespace tdetail { template<class Expr> struct fill_tmps_helper { const Expr& expr; fill_tmps_helper(const Expr& e) : expr(e) {}; template<class T> T create() const {return rules::instantiate_temporaries<Expr, T>::get(expr);} }; } // tdetail template <class Expr> tdetail::fill_tmps_helper<Expr> temporaries_filler(const Expr& e) { return tdetail::fill_tmps_helper<Expr>(e); } // A helper to "evaluate" a single term, independent of whether or not it is // actually an expression template template<class T, class Enable = void> struct evaluation_helper { typedef typename traits::basetype<T>::type type; typedef typename traits::forwarding<type>::type ftype; typedef ftype etype; static ftype get(const type& t) {return t;} typedef empty_tuple temporaries_t; }; template<class T> struct evaluation_helper<T, typename mp::enable_if<traits::is_lazy_expr<T> >::type> { typedef typename T::evaluated_t type; typedef const typename T::evaluated_t& ftype; typedef type etype; static type get(const T& t) {return t.evaluate();} typedef typename T::ev_traits_t::temp_rule_t::temporaries_t temporaries_t; }; /////////////////////////////////////////////////////////////////////////// // Helper to evaluate n terms /////////////////////////////////////////////////////////////////////////// // The template argument is an arbitrary argument tuple template<class Args, class Enable = void> struct evaluate_n; // Count the number of non-immediate terms in arguments template<class Args> struct count_nonimm { static const unsigned val = traits::is_lazy_expr<typename Args::head_t>::val + count_nonimm<typename Args::tail_t>::val; }; template<> struct count_nonimm<empty_tuple> { static const unsigned val = 0; }; template<class Args> struct evaluated_args_tuple { typedef typename tools::evaluation_helper<typename Args::head_t>::ftype evt; typedef typename evaluated_args_tuple<typename Args::tail_t>::type tail_t; typedef tuple<evt, tail_t> type; }; template<> struct evaluated_args_tuple<empty_tuple> { typedef empty_tuple type; }; namespace tdetail { // Unoptimized evaluation (in order) // The constructor sets up any local temporaries (coming from non-merging). // Then init does the actual computation. Note that init chains at the end // (in contrast to construction), so we do evaluate in order. template<class Args, class Enable = void> struct evaluate_n_unopt { // case where head is immediate typedef evaluate_n_unopt<typename Args::tail_t> next_t; typedef typename next_t::temporaries_t temporaries_t; typedef typename Args::head_t headr_t; next_t next; headr_t res; headr_t gethead() const { return res; } void init(const Args& args, temporaries_t temps) { next.init(args.tail, temps); } evaluate_n_unopt(const Args& args) : next(args.tail), res(args.head) {} }; template<> struct evaluate_n_unopt<empty_tuple> { // basecase typedef empty_tuple temporaries_t; void init(empty_tuple, empty_tuple) {} evaluate_n_unopt(empty_tuple) {} }; template<class Args> struct evaluate_n_unopt<Args, typename mp::enable_if<mp::and_< traits::is_lazy_expr<typename Args::head_t>, mp::not_<traits::use_temporary_merging< typename Args::head_t::evaluated_t> > > >::type> { // Case with non-merging lazy head typedef evaluate_n_unopt<typename Args::tail_t> next_t; typedef typename Args::head_t expr_t; typedef typename expr_t::ev_traits_t::temp_rule_t rule_t; typedef typename rule_t::return_t tmp_t; typedef mp::merge_tuple<typename rule_t::temporaries_t, typename next_t::temporaries_t> merger; typedef typename merger::type temporaries_t; typedef typename traits::forwarding<tmp_t>::type headr_t; next_t next; tmp_t tmp; headr_t gethead() const { return tmp; } evaluate_n_unopt(const Args& args) : next(args.tail), tmp( rules::instantiate_temporaries<expr_t, tmp_t>::get(args.head)) {} void init(const Args& args, temporaries_t temps) { rule_t::doit(args.head._data(), merger::get_first(temps), &tmp); next.init(args.tail, merger::get_second(temps)); } }; template<class Args> struct evaluate_n_unopt<Args, typename mp::enable_if<mp::and_< traits::is_lazy_expr<typename Args::head_t>, traits::use_temporary_merging< typename Args::head_t::evaluated_t> > >::type> { // Case with merging lazy head typedef evaluate_n_unopt<typename Args::tail_t> next_t; typedef typename Args::head_t expr_t; typedef typename expr_t::ev_traits_t::temp_rule_t rule_t; typedef typename rule_t::return_t tmp_t; typedef mp::merge_tuple<typename rule_t::temporaries_t, tuple<tmp_t*, typename next_t::temporaries_t> > merger; typedef typename merger::type temporaries_t; typedef typename traits::forwarding<tmp_t>::type headr_t; next_t next; tmp_t* tmp; headr_t gethead() const { return *tmp; } evaluate_n_unopt(const Args& args) : next(args.tail) {} void init(const Args& args, temporaries_t temps) { tmp = merger::get_second(temps).head; rule_t::doit(args.head._data(), merger::get_first(temps), tmp); next.init(args.tail, merger::get_second(temps).tail); } }; template<class Args, unsigned n> struct unopt_get { typedef unopt_get<typename Args::tail_t, n-1> getn; typedef typename getn::type type; static type get(const evaluate_n_unopt<Args>& e) {return getn::get(e.next);} }; template<class Args> struct unopt_get<Args, 0> { typedef evaluate_n_unopt<Args> evalt; typedef typename evalt::headr_t type; static type get(const evalt& e) {return e.gethead();} }; template<class Args> struct unopt_gettuple { typedef unopt_gettuple<typename Args::tail_t> next; typedef evaluate_n_unopt<Args> eval_t; typedef tuple<typename eval_t::headr_t, typename next::type> type; static type get(const eval_t& e) { return type(e.gethead(), next::get(e.next)); } }; template<> struct unopt_gettuple<empty_tuple> { typedef empty_tuple type; template<class T> static type get(const T&) {return empty_tuple();} }; // Optimized case with precisely two non-immediates template<class Args, unsigned found = 0, class Enable = void> struct evaluate_n_2_analyze { typedef evaluate_n_2_analyze<typename Args::tail_t, found> next; static const unsigned first = next::first + 1; static const unsigned second = next::second + 1; }; template<class Args> struct evaluate_n_2_analyze<Args, 0, typename mp::enable_if<traits::is_lazy_expr<typename Args::head_t> >::type> { typedef evaluate_n_2_analyze<typename Args::tail_t, 1> next; static const unsigned first = 0; static const unsigned second = next::second + 1; }; template<class Args> struct evaluate_n_2_analyze<Args, 1, typename mp::enable_if<traits::is_lazy_expr<typename Args::head_t> >::type> { static const unsigned first = 0; static const unsigned second = 0; }; template<class Expr1, class Expr2, class Enable = void> struct evaluate_2; // Case where neither is immediate, no merging template<class Expr1, class Expr2> struct evaluate_2<Expr1, Expr2, typename mp::enable_if<mp::and_< traits::is_lazy_expr<Expr1>, traits::is_lazy_expr<Expr2>, mp::not_<traits::use_temporary_merging<typename Expr1::evaluated_t> >, mp::not_<traits::use_temporary_merging<typename Expr2::evaluated_t> > > >::type> { private: typedef typename Expr1::ev_traits_t::temp_rule_t rule1_t; typedef typename Expr2::ev_traits_t::temp_rule_t rule2_t; public: typedef typename rule1_t::return_t return1_t; typedef typename rule2_t::return_t return2_t; private: typedef typename rule1_t::temporaries_t temporaries1_t; typedef typename rule2_t::temporaries_t temporaries2_t; typedef mp::merge_tuple<temporaries1_t, temporaries2_t> merger; return1_t tmp1; return2_t tmp2; public: typedef typename merger::type temporaries_t; evaluate_2(temporaries_t temps, const Expr1& e1, const Expr2& e2) : tmp1(rules::instantiate_temporaries<Expr1, return1_t>::get(e1)), tmp2(rules::instantiate_temporaries<Expr2, return2_t>::get(e2)) { rule1_t::doit(e1._data(), merger::get_first(temps), &tmp1); rule2_t::doit(e2._data(), merger::get_second(temps), &tmp2); } const return1_t& get1() const {return tmp1;} const return2_t& get2() const {return tmp2;} }; // Case where neither is immediate, first has merging, second does not template<class Expr1, class Expr2> struct evaluate_2<Expr1, Expr2, typename mp::enable_if<mp::and_< traits::is_lazy_expr<Expr1>, traits::is_lazy_expr<Expr2>, traits::use_temporary_merging<typename Expr1::evaluated_t>, mp::not_<traits::use_temporary_merging<typename Expr2::evaluated_t> > > >::type> { private: typedef typename Expr1::ev_traits_t::temp_rule_t rule1_t; typedef typename Expr2::ev_traits_t::temp_rule_t rule2_t; public: typedef typename rule1_t::return_t return1_t; typedef typename rule2_t::return_t return2_t; private: typedef typename rule1_t::temporaries_t temporaries1_t; typedef typename rule2_t::temporaries_t temporaries2_t; typedef mp::merge_tuple<typename mp::make_tuple<return1_t*>::type, temporaries1_t> merger1; typedef mp::merge_tuple<typename merger1::type, temporaries2_t> merger2; return2_t tmp2; return1_t* ret1; public: typedef typename merger2::type temporaries_t; evaluate_2(temporaries_t temps, const Expr1& e1, const Expr2& e2) : tmp2(rules::instantiate_temporaries<Expr2, return2_t>::get(e2)) { rule2_t::doit(e2._data(), merger2::get_second(temps), &tmp2); ret1 = merger1::get_first(merger2::get_first(temps)).head; rule1_t::doit(e1._data(), merger1::get_second(merger2::get_first(temps)), ret1); } const return1_t& get1() const {return *ret1;} const return2_t& get2() const {return tmp2;} }; // Case where neither is immediate, second has merging, first does not template<class Expr1, class Expr2> struct evaluate_2<Expr1, Expr2, typename mp::enable_if<mp::and_< traits::is_lazy_expr<Expr1>, traits::is_lazy_expr<Expr2>, traits::use_temporary_merging<typename Expr2::evaluated_t>, mp::not_<traits::use_temporary_merging<typename Expr1::evaluated_t> > > >::type> { // XXX this is copy-paste from above case where right is immediate private: typedef evaluate_2<Expr2, Expr1> ev2_t; ev2_t ev2; public: typedef typename ev2_t::return1_t return2_t; typedef typename ev2_t::return2_t return1_t; typedef typename ev2_t::temporaries_t temporaries_t; evaluate_2(temporaries_t temps, const Expr1& e1, const Expr2& e2) : ev2(temps, e2, e1) {}; const return1_t& get1() const {return ev2.get2();} const return2_t& get2() const {return ev2.get1();} }; // Case where neither is immediate, all merging template<class Expr1, class Expr2> struct evaluate_2<Expr1, Expr2, typename mp::enable_if<mp::and_< traits::is_lazy_expr<Expr1>, traits::is_lazy_expr<Expr2>, traits::use_temporary_merging<typename Expr1::evaluated_t>, traits::use_temporary_merging<typename Expr2::evaluated_t> > >::type> { private: typedef typename Expr1::ev_traits_t::temp_rule_t rule1_t; typedef typename Expr2::ev_traits_t::temp_rule_t rule2_t; public: typedef typename rule1_t::return_t return1_t; typedef typename rule2_t::return_t return2_t; private: typedef typename rule1_t::temporaries_t temporaries1_t; typedef typename rule2_t::temporaries_t temporaries2_t; template<class E1, class E2, class Enable> friend struct evaluate_2; // We can either evaluate the Expr1 first and then Expr2, or the other // way round. We would like to choose the most efficient strategy. // Since we have no access to other metrics, we compare the number of // temporaries required (see typedef of doit below). struct doit_1 { typedef mp::merge_tuple<typename mp::make_tuple<return2_t*>::type, temporaries2_t> merger2; typedef mp::merge_tuple<tuple<return1_t*, typename merger2::type>, temporaries1_t> merger1; typedef typename merger1::type temporaries_t; static void init(temporaries_t temps, const Expr1& e1, const Expr2& e2, return1_t*& ret1, return2_t*& ret2) { temporaries1_t temps1 = merger1::get_second(temps); temporaries2_t temps2 = merger2::get_second(merger1::get_first(temps).tail); ret1 = merger1::get_first(temps).head; ret2 = merger2::get_first(merger1::get_first(temps).tail).head; rule1_t::doit(e1._data(), temps1, ret1); rule2_t::doit(e2._data(), temps2, ret2); } }; struct doit_2 { typedef typename evaluate_2<Expr2, Expr1>::doit_1 doit_other; typedef typename doit_other::temporaries_t temporaries_t; static void init(temporaries_t temps, const Expr1& e1, const Expr2& e2, return1_t*& ret1, return2_t*& ret2) { doit_other::init(temps, e2, e1, ret2, ret1); } }; typedef typename mp::if_v< (doit_1::temporaries_t::len <= doit_2::temporaries_t::len), doit_1, doit_2>::type doit; return1_t* ret1; return2_t* ret2; public: typedef typename doit::temporaries_t temporaries_t; evaluate_2(temporaries_t temps, const Expr1& e1, const Expr2& e2) { doit::init(temps, e1, e2, ret1, ret2); } const return1_t& get1() const {return *ret1;} const return2_t& get2() const {return *ret2;} }; template<unsigned first, unsigned second, unsigned n> struct evaluate_n_2_get { template<class Args, class First, class Second> static typename mp::tuple_get<Args, n>::type get(const Args& args, const First&, const Second&) { return mp::tuple_get<Args, n>::get(args); } }; template<unsigned first, unsigned second> struct evaluate_n_2_get<first, second, first> { template<class Args, class First, class Second> static const First& get(const Args&, const First& f, const Second&) { return f; } }; template<unsigned first, unsigned second> struct evaluate_n_2_get<first, second, second> { template<class Args, class First, class Second> static const Second& get(const Args&, const First&, const Second& s) { return s; } }; template<class Tuple, unsigned n = 0> struct evaluate_n_2_gettuple { template<class T> static Tuple get(const T& t) { return Tuple(t.template get<n>(), evaluate_n_2_gettuple<typename Tuple::tail_t, n+1>::get(t)); } }; template<unsigned n> struct evaluate_n_2_gettuple<empty_tuple, n> { template<class T> static empty_tuple get(const T&) {return empty_tuple();} }; } // tdetail template<class Args, class Enable> struct evaluate_n { typedef tdetail::evaluate_n_unopt<Args> eval_t; typedef typename eval_t::temporaries_t temporaries_t; typedef typename tdetail::unopt_gettuple<Args>::type evtup_t; eval_t eval; evaluate_n(const Args& args, temporaries_t temps) : eval(args) { eval.init(args, temps); } template<unsigned n> typename tdetail::unopt_get<Args, n>::type get() const { return tdetail::unopt_get<Args, n>::get(eval); } evtup_t gettuple() const { return tdetail::unopt_gettuple<Args>::get(eval); } }; template<class Args> struct evaluate_n<Args, typename mp::enable_if_v<count_nonimm<Args>::val == 2>::type> { typedef tdetail::evaluate_n_2_analyze<Args> analysis; static const unsigned first = analysis::first; static const unsigned second = analysis::second; typedef mp::tuple_get<Args, first> getfirst; typedef mp::tuple_get<Args, second> getsecond; typedef typename getfirst::type first_t; typedef typename getsecond::type second_t; typedef tdetail::evaluate_2<first_t, second_t> ev_t; typedef typename ev_t::temporaries_t temporaries_t; const Args& args; ev_t ev; evaluate_n(const Args& a, temporaries_t temps) : args(a), ev(temps, getfirst::get(a), getsecond::get(a)) {} typedef typename evaluated_args_tuple<Args>::type evtup_t; template<unsigned n> typename mp::tuple_get<evtup_t, n>::type get() const { return tdetail::evaluate_n_2_get<first, second, n>::get( args, ev.get1(), ev.get2()); } evtup_t gettuple() const { return tdetail::evaluate_n_2_gettuple<evtup_t>::get(*this); } }; /////////////////////////////////////////////////////////////////////////// // Helper to evaluate three homogeneous terms /////////////////////////////////////////////////////////////////////////// // // Evaluation using ternary operators is actually surprisingly hard. // Consider e.g. a + b*c. The number of temporaries needed for this depends // on whether or not b, c are immediates, and on the numbers of temporaries // needed for each non-immediate expression. namespace tdetail { // This struct deals with the difficulties in whether b or c might be // immediate. template<class T, class Left, class rigth1_t, class right2_t, bool bimm, bool cimm> struct ternary_hhelper; // To be specialised below. } // tdetail // The following struct can be used to simplify writing evaluation rules which // use ternary operations (addmul, submul). // // In the situation of a + b*c, the optimization can be applied if // - the result goes to a temporary (i.e. we can write to it prematurely) // - a is not an immediate // - a, b, c are of the same type, and addmul is available for this type // If so, one needs to evaluate a into the return location and b, c into // temporaries; after that addmul can be applied. // // The ternary_helper facilitates both the checking if we are in the right // situation and the intermediate evaluations. Instantiate it with // "T" being your ground type (for which addmul is implemented), "Left" the type // of a, "Right1" the type of b and "Right2" the type of c. // Then the member enable::type can be used in SFINAE situations to // conditionally enable a template only if we are in the addmul situation. // The member type "temporaries_t" and static member function "doit" can be used // to evaluate the intermediate terms. // // It may sometimes be useful to preclude a certain type of expression for a. // (E.g. one needs rules for both a + b*c and b*c + a, but then which of these // applies to b*c + a*d?) To do this, pass the operation you want to exclude in // "disable_op". // // NOTE: in the current implementation, ternary_helper only works with // *homogeneous* expressions. These are defined to be expressions evaluating to // type T, which only need temporaries of type T. // This condition is included in the checks done by the enable member type. // NOTE: This implementation does not honor use_temporary_merging! // template<class T, class Left, class Right1, class Right2, class disable_op = void, class Enable = void> struct ternary_helper { }; template<class T, class Left, class Right1, class Right2, class disable_op> struct ternary_helper<T, Left, Right1, Right2, disable_op, typename mp::enable_if<mp::and_< traits::is_lazy_expr<Left>, traits::is_expression<typename traits::basetype<Right1>::type>, traits::is_expression<typename traits::basetype<Right1>::type> > >::type> { typedef typename traits::basetype<Right1>::type right1_t; typedef typename traits::basetype<Right2>::type right2_t; typedef typename Left::ev_traits_t::temp_rule_t evl; typedef tools::evaluation_helper<right1_t> evhr1; typedef tools::evaluation_helper<right2_t> evhr2; typedef mp::enable_if<mp::and_< traits::is_homogeneous_tuple<typename evl::temporaries_t, T*>, traits::is_homogeneous_tuple<typename evhr1::temporaries_t, T*>, traits::is_homogeneous_tuple<typename evhr2::temporaries_t, T*>, traits::is_homogeneous_tuple< typename mp::make_tuple< typename evl::return_t, typename evhr1::type, typename evhr2::type>::type, T>, mp::not_<mp::equal_types<typename Left::operation_t, disable_op> > > > enable; typedef tdetail::ternary_hhelper<T, Left, right1_t, right2_t, traits::is_immediate<right1_t>::val, traits::is_immediate<right2_t>::val> inner; typedef typename inner::temporaries_t temporaries_t; // evaluate left into res, rigth1 and right2 to arbitrary location, // set toright1, toright2 to these locations static void doit(const Left& left, const right1_t& right1, const right2_t& right2, temporaries_t temps, T* res, const T*& toright1, const T*& toright2) { inner::doit(left, right1, right2, temps, res, toright1, toright2); } }; namespace tdetail { // Case where both are immediate. template<class T, class Left, class right1_t, class right2_t> struct ternary_hhelper<T, Left, right1_t, right2_t, true, true> { typedef typename Left::ev_traits_t::temp_rule_t evl; static const unsigned norig = evl::temporaries_t::len; static const unsigned ntemps = FLINT_MAX(norig, 1); typedef typename mp::make_homogeneous_tuple<T*, ntemps>::type temporaries_t; static void doit(const Left& left, const right1_t& right1, const right2_t& right2, temporaries_t temps, T* res, const T*& toright1, const T*& toright2) { evl::doit(left._data(), mp::htuples::extract<norig>(temps), res); toright1 = &right1; toright2 = &right2; } }; // If c is immediate but b is not, there are still two subcases. // Let t1 be the number of temporaries needed to evaluate a, and // t2 the number for b. If t1 >= t2, then we need to evaluate a first. // Otherwise b. // In any case, the number of temporaries is at least two (for the two return // values), and generically equal to the maximum of t1 and t2. If however // t1 == t2, then we need an additional temporary. template<class T, class Left, class right1_t, class right2_t, bool t1_ge_t2> struct ternary_hhelper_1imm; // Case where t1 >= t2 template<class T, class Left, class right1_t, class right2_t> struct ternary_hhelper_1imm<T, Left, right1_t, right2_t, true> { typedef typename Left::ev_traits_t::temp_rule_t evl; typedef typename right1_t::ev_traits_t::temp_rule_t evr; static const unsigned t1 = evl::temporaries_t::len; static const unsigned t2 = evr::temporaries_t::len; // t1 >= t2 template<class Temps> static void doit(const Left& left, const right1_t& right1, Temps temps, T* res, const T*& toright1) { evl::doit(left._data(), mp::htuples::extract<t1>(temps), res); typename Temps::tail_t nores = mp::htuples::removeres(temps, res); evr::doit(right1._data(), mp::htuples::extract<t2>(nores), nores.head); toright1 = nores.head; } }; // Case where t1 < t2 template<class T, class Left, class right1_t, class right2_t> struct ternary_hhelper_1imm<T, Left, right1_t, right2_t, false> { typedef typename Left::ev_traits_t::temp_rule_t evl; typedef typename right1_t::ev_traits_t::temp_rule_t evr; static const unsigned t1 = evl::temporaries_t::len; static const unsigned t2 = evr::temporaries_t::len; // t1 < t2 template<class Temps> static void doit(const Left& left, const right1_t& right1, Temps temps, T* res, const T*& toright1) { typedef typename Temps::tail_t tail_t; tail_t nores = mp::htuples::removeres(temps, res); evr::doit(right1._data(), mp::htuples::extract<t2>(temps), nores.head); toright1 = nores.head; evl::doit(left._data(), mp::htuples::extract<t1>(tail_t(res, nores.tail)), res); } }; // Case where c is immediate. template<class T, class Left, class right1_t, class right2_t> struct ternary_hhelper<T, Left, right1_t, right2_t, false, true> { typedef typename Left::ev_traits_t::temp_rule_t evl; typedef tools::evaluation_helper<right1_t> evhr1; static const unsigned t1 = evl::temporaries_t::len; static const unsigned t2 = evhr1::temporaries_t::len; static const unsigned ntemps = FLINT_MAX(2, FLINT_MAX(t1, t2) + (t1 == t2)); typedef ternary_hhelper_1imm<T, Left, right1_t, right1_t, t1 >= t2> thh1; typedef typename mp::make_homogeneous_tuple<T*, ntemps>::type temporaries_t; static void doit(const Left& left, const right1_t& right1, const right2_t& right2, temporaries_t temps, T* res, const T*& toright1, const T*& toright2) { toright2 = &right2; thh1::doit(left, right1, temps, res, toright1); } }; // Case where b is immediate. template<class T, class Left, class right1_t, class right2_t> struct ternary_hhelper<T, Left, right1_t, right2_t, true, false> { typedef ternary_hhelper<T, Left, right2_t, right1_t, false, true> thh; typedef typename thh::temporaries_t temporaries_t; static void doit(const Left& left, const right1_t& right1, const right2_t& right2, temporaries_t temps, T* res, const T*& toright1, const T*& toright2) { thh::doit(left, right2, right1, temps, res, toright2, toright1); } }; // Case where neither is immediate. template<class T, class Left, class right1_t, class right2_t> struct ternary_hhelper<T, Left, right1_t, right2_t, false, false> { typedef typename Left::ev_traits_t::temp_rule_t evl; typedef typename right1_t::ev_traits_t::temp_rule_t evr1; typedef typename right2_t::ev_traits_t::temp_rule_t evr2; static const unsigned t1 = evl::temporaries_t::len; static const unsigned t2 = evr1::temporaries_t::len; static const unsigned t3 = evr2::temporaries_t::len; // m1, m2, m3 is t1, t2, t3 reordered s.t. m1 >= m2 >= m3 static const unsigned m1 = FLINT_MAX(t1, FLINT_MAX(t2, t3)); static const unsigned m3 = FLINT_MIN(t1, FLINT_MIN(t2, t3)); static const unsigned m2 = t1 + t2 + t3 - m1 - m3; // The following is obtained by case analysis static const unsigned ntemps = (t1 == t2 && t2 == t3) ? FLINT_MAX(3, t1+2) : // all equal ((m1 > m2 && m2 > m3) ? FLINT_MAX(3, m1) : // all distinct (m1 == m2 ? FLINT_MAX(m1+1, 3) // first two equal : FLINT_MAX(m1, FLINT_MAX(m2+2, 3)))); // second two equal typedef typename mp::make_homogeneous_tuple<T*, ntemps>::type temporaries_t; struct resaccess { T* res; resaccess(T* r) : res(r) {}; template<class Eval, class Temps, class Data> typename Temps::tail_t doit(const Data& d, Temps temps) { Eval::doit(d, mp::htuples::extract<Eval::temporaries_t::len>(temps), res); return mp::htuples::extract<Temps::len-1>(temps); } }; struct toaccess { const T*& right; toaccess(const T*& r) : right(r) {}; template<class Eval, class Temps, class Data> typename Temps::tail_t doit(const Data& d, Temps temps) { Eval::doit(d, mp::htuples::extract<Eval::temporaries_t::len>(temps), temps.head); right = temps.head; return temps.tail; } }; struct doit_really { template<class E1, class E2, class E3, class A1, class A2, class A3> static void doit(const E1& e1, const E2& e2, const E3& e3, temporaries_t temps, A1 a1, A2 a2, A3 a3) { typedef typename E1::ev_traits_t::temp_rule_t ev1; typedef typename E2::ev_traits_t::temp_rule_t ev2; typedef typename E3::ev_traits_t::temp_rule_t ev3; a3.template doit<ev3>(e3._data(), a2.template doit<ev2>(e2._data(), a1.template doit<ev1>(e1._data(), temps))); } }; struct dont_doit { template<class E1, class E2, class E3, class A1, class A2, class A3> static void doit(const E1& e1, const E2& e2, const E3& e3, temporaries_t temps, A1 a1, A2 a2, A3 a3) { } }; template<class E1, class E2, class E3, class A1, class A2, class A3> static void doit_sort(const E1& e1, const E2& e2, const E3& e3, temporaries_t temps, A1 a1, A2 a2, A3 a3) { typedef typename E1::ev_traits_t::temp_rule_t ev1; typedef typename E2::ev_traits_t::temp_rule_t ev2; typedef typename E3::ev_traits_t::temp_rule_t ev3; static const unsigned u1 = ev1::temporaries_t::len; static const unsigned u2 = ev2::temporaries_t::len; static const unsigned u3 = ev3::temporaries_t::len; if(u1 < u2) return doit_sort(e2, e1, e3, temps, a2, a1, a3); if(u2 < u3) return doit_sort(e1, e3, e2, temps, a1, a3, a2); // If we reach this point, u1 >= u2 >= u3. // However, even if this is not the case, the following line (and // everything it instantiates) still has to compile. mp::if_v<(u1 >= u2 && u2 >= u3), doit_really, dont_doit>::type::doit( e1, e2, e3, temps, a1, a2, a3); } static void doit(const Left& left, const right1_t& right1, const right2_t& right2, temporaries_t temps, T* res, const T*& toright1, const T*& toright2) { // We re-order the temporaries in such a way that res is at the // very end. When evaluating things in the correct order, it is then // always correct to take temporaries from the front, and drop them // from the front. temporaries_t temps_reordered = mp::concat_tuple< typename temporaries_t::tail_t, typename mp::make_tuple<T*>::type>::doit( mp::htuples::removeres(temps, res), mp::make_tuple<T*>::make(res)); doit_sort(left, right1, right2, temps_reordered, resaccess(res), toaccess(toright1), toaccess(toright2)); } }; } // tdetail // A helper condition for use with FLINT_DEFINE_*_COND? template<class T> struct is_bool : mp::equal_types<T, bool> { }; } // tools } // flint #endif /* Copyright (C) 2013 Tom Bachmann This file is part of FLINT. FLINT is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See <https://www.gnu.org/licenses/>. */ #ifndef CXX_EXPRESSION_H #define CXX_EXPRESSION_H // TODO // * static asserts #include <iosfwd> #include <string> #include <cstdio> namespace flint { namespace detail { // Helper traits used by the "expression" class, in particular the evaluate() // method. This is the general (i.e. non-immediate) case, // which requires actual work. template<class Operation, class Expr, class Data> struct evaluation_traits { typedef typename Expr::derived_t derived_t; typedef typename mp::find_evaluation< Operation, Data, false>::type rule_t; typedef typename mp::find_evaluation< Operation, Data, true>::type temp_rule_t; typedef typename rule_t::return_t evaluation_return_t; typedef evaluation_return_t evaluated_t; static evaluation_return_t evaluate(const derived_t& from) { evaluated_t res = rules::instantiate_temporaries<derived_t, evaluated_t>::get(from); evaluate_into_fresh(res, from); return res; } template<class T> static void evaluate_into(T& to, const derived_t& from) { typedef mp::back_tuple<typename rule_t::temporaries_t> back_t; typename back_t::type temps_backing = mp::htuples::fill<typename back_t::type>( tools::temporaries_filler(from)); typename rule_t::temporaries_t temps; back_t::init(temps, temps_backing, 0); rule_t::doit(from._data(), temps, &to); } static void evaluate_into_fresh(evaluation_return_t& to, const derived_t& from) { typedef mp::back_tuple< typename temp_rule_t::temporaries_t, evaluation_return_t > back_t; typename back_t::type temps_backing = mp::htuples::fill<typename back_t::type>( tools::temporaries_filler(from)); typename temp_rule_t::temporaries_t temps; back_t::init(temps, temps_backing, &to); temp_rule_t::doit(from._data(), temps, &to); } }; // This is the special case of an immediate argument, where "evaluation" is // at most assignment. template<class Expr, class Data> struct evaluation_traits<operations::immediate, Expr, Data> { typedef typename Expr::derived_t derived_t; typedef typename Expr::derived_t evaluated_t; typedef evaluated_t& evaluation_return_t; static evaluated_t& evaluate(derived_t& d) {return d;} static const evaluated_t& evaluate(const derived_t& d) {return d;} template<class T> static void evaluate_into(T& to, const derived_t& from) { rules::assignment<T, derived_t>::doit(to, from); } static void evaluate_into_fresh(derived_t& to, const derived_t& from) { evaluate_into(to, from); } }; } // detail // The main expression template class. // // The argument Derived must have the following form: // struct derived // { // template<class Operation, class Data> // struct type // { // typedef XYZ result; // }; // }; // See derived_wrapper below for a common example. // // Note that, while Data does not have to be default constructible, // it *does* need to be copy-constructible, and have a working destructor. template<class Derived, class Operation, class Data> class expression { private: Data data; protected: explicit expression(const Data& d) : data(d) {} public: // internal -- see is_expression implementation. typedef void IS_EXPRESSION_MARKER; typedef detail::evaluation_traits<Operation, expression, Data> ev_traits_t; typedef typename Derived::template type<Operation, Data>::result derived_t; typedef typename ev_traits_t::evaluated_t evaluated_t; typedef typename ev_traits_t::evaluation_return_t evaluation_return_t; typedef Data data_t; typedef Operation operation_t; private: derived_t& downcast() {return *static_cast<derived_t*>(this);} const derived_t& downcast() const { return *static_cast<const derived_t*>(this); } // Some helpers for initialization, since it is not possible to // conditionally enable constructors in C++98 template<class T> static data_t get_data(const T& t, typename mp::disable_if<traits::is_lazy_expr<T> >::type* = 0) { return data_t(t); } template<class T> static data_t get_data(T& t, typename mp::disable_if<traits::is_lazy_expr<T> >::type* = 0) { return data_t(t); } template<class T> static data_t get_data(const T& t, typename mp::enable_if<traits::is_lazy_expr<T> >::type* = 0, typename mp::disable_if< mp::equal_types<typename T::evaluated_t, derived_t> >::type* = 0) { return data_t(t.evaluate()); } template<class T> static data_t get_data(const T& t, typename mp::enable_if<traits::is_lazy_expr<T> >::type* = 0, typename mp::enable_if< mp::equal_types<typename T::evaluated_t, derived_t> >::type* = 0) { return data_t(t.evaluate()._data()); } // Invoke the data copy constructor when appropriate static data_t get_data(const derived_t& o) { return data_t(o._data()); } static data_t get_data(derived_t& o) { return data_t(o._data()); } // Having the empty constructor here delays its instantiation, and allows // compiling even if data is *not* default constructible. static data_t get_data() {return data_t();} public: // forwarded constructors template<class T> explicit expression(const T& t) : data(get_data(t)) {} template<class T> explicit expression(T& t) : data(get_data(t)) {} template<class T, class U> expression(const T& t, const U& u) : data(t, u) {} template<class T, class U> expression(T& t, const U& u) : data(t, u) {} template<class T, class U, class V> expression(const T& t, const U& u, const V& v) : data(t, u, v) {} template<class T, class U, class V> expression(T& t, const U& u, const V& v) : data(t, u, v) {} template<class T, class U, class V, class W> expression(const T& t, const U& u, const V& v, const W& w) : data(t, u, v, w) {} template<class T, class U, class V, class W> expression(T& t, const U& u, const V& v, const W& w) : data(t, u, v, w) {} expression() : data(get_data()) {} expression& operator=(const expression& o) { this->set(o.downcast()); return *this; } // See rules::instantiate_temporaries for explanation. evaluated_t create_temporary() const { return evaluated_t(); } Data& _data() {return data;} const Data& _data() const {return data;} void print(std::ostream& o) const { tools::print_using_str<evaluated_t>::doit(evaluate(), o); } std::string to_string(int base = 10) const { return rules::to_string<evaluated_t>::get(evaluate(), base); } template<class T> T to() const { return rules::conversion<T, evaluated_t>::get(evaluate()); } int print(FILE* f = stdout) const { return rules::cprint<evaluated_t>::doit(f, evaluate()); } int print_pretty(FILE* f = stdout) const { return rules::print_pretty<evaluated_t>::doit(f, evaluate()); } template<class T> int print_pretty(const T& extra, FILE* f = stdout) const { return rules::print_pretty<evaluated_t>::doit(f, evaluate(), extra); } int read(FILE* f = stdin) { return rules::read<derived_t>::doit(f, downcast()); } typename traits::make_const<evaluation_return_t>::type evaluate() const { return ev_traits_t::evaluate(downcast()); } evaluation_return_t evaluate() {return ev_traits_t::evaluate(downcast());} template<class T> void set(const T& t, typename mp::enable_if<traits::is_expression<T> >::type* = 0, typename mp::enable_if<traits::can_evaluate_into< derived_t, typename T::evaluated_t> >::type* = 0) { T::ev_traits_t::evaluate_into(downcast(), t); } template<class T> void set(const T& t, typename mp::enable_if<traits::is_expression<T> >::type* = 0, typename mp::disable_if<traits::can_evaluate_into< derived_t, typename T::evaluated_t> >::type* = 0) { rules::assignment<derived_t, typename T::evaluated_t>::doit( downcast(), t.evaluate()); } template<class T> void set(const T& t, typename mp::disable_if<traits::is_expression<T> >::type* = 0) { rules::assignment<derived_t, T>::doit(downcast(), t); } template<class T> bool equals(const T& t, typename mp::enable_if<traits::is_lazy_expr<T> >::type* = 0) const { return equals(t.evaluate()); } template<class T> bool equals(const T& t, typename mp::disable_if<traits::is_lazy_expr<T> >::type* = 0) const { return tools::equals_using_cmp<evaluated_t, T>::get(evaluate(), t); } template<class Op, class NData> struct make_helper { typedef typename Derived::template type<Op, NData>::result type; static type make(const NData& ndata) { return type(ndata); } }; }; // If your expression template is of the form // template<class Operation, class Data> // class my_expression ... // then derived_wrapper<my_expression> is a valid argument for Derived in // the expression class above. template<template<class O, class D> class Derived> struct derived_wrapper { template<class Operation, class Data> struct type { typedef Derived<Operation, Data> result; }; }; // If your expression template is of the form // template<class Extra, class Operation, class Data> // class my_expression2 ... // where Extra is some extra information which should be passed on unchanged, // then derived_wrapper2<my_expression2, Extra> is a valid argument for Derived // in the expression class above. template<template<class E, class O, class D> class Derived, class Extra> struct derived_wrapper2 { template<class Operation, class Data> struct type { typedef Derived<Extra, Operation, Data> result; }; }; // operators namespace detail { // These traits determine how arguments of an expression template are stored. // E.g. (e1 + e2) yields a new expression template with a two-argument tuple // as Data. If e1 is an immediate, then we want to (usually) store it by // reference, to avoid copies. If not, we can just store by value (since // copying e1 just copies the references anyway) and avoid indirection. // (Similarly for e2.) template<class Expr> struct storage_traits : mp::if_< traits::is_immediate<Expr>, typename traits::forwarding<Expr>::type, Expr > { }; // See tuple.h. template<> struct storage_traits<detail::UNUSED> {typedef detail::UNUSED type;}; template<class ev_t, class Op, class type> struct nary_op_helper_step2 { typedef typename ev_t::return_t Expr; typedef typename Expr::template make_helper<Op, type> make_helper; typedef typename make_helper::type return_t; }; template<class Op, class type> struct nary_op_helper_step2<rules::UNIMPLEMENTED, Op, type> { struct return_t { }; struct make_helper { }; }; // Helper to determine the return type of an expression, where Data is already // the correct tuple type. // The step1/step2 splitting above is necessary to avoid compiler errors in // case there is not actually any rule. template<class Op, class Data> struct nary_op_helper { typedef typename mp::find_evaluation<Op, Data, true>::type ev_t; typedef nary_op_helper_step2<ev_t, Op, Data> nohs2; typedef typename nohs2::return_t return_t; typedef typename nohs2::make_helper make_helper; typedef traits::is_implemented<ev_t> cond; typedef mp::enable_if<cond, return_t> enable; }; template<class Op, class Maker> struct nary_op_helper_maker : nary_op_helper<Op, typename Maker::type> { typedef Maker maker; }; #define FLINTXX_NARY_OP_HELPER_MACRO(arg) typename storage_traits< arg >::type // nary_op_helper<Op, Arg1, Arg2, ...> invokes nary_op_helper with the correct // tuple type as argument. template<class Op, FLINTXX_MAKE_TUPLE_TEMPLATE_ARGS> struct nary_op_helper2 : nary_op_helper_maker<Op, mp::make_tuple< FLINTXX_MAKE_TUPLE_TYPES_APPLYMACRO(FLINTXX_NARY_OP_HELPER_MACRO) > > { typedef nary_op_helper2 noh2; static typename noh2::return_t make(FLINTXX_MAKE_TUPLE_FUNC_ARGS) { return noh2::make_helper::make(noh2::maker::make( FLINTXX_MAKE_TUPLE_FUNC_ARG_NAMES)); } }; // Special casing for binary operators. template<class Expr1, class Op, class Expr2> struct binary_op_helper : nary_op_helper2<Op, Expr1, Expr2> { }; // Special casing for unary operations. template<class Op, class Expr> struct unary_op_helper : nary_op_helper2<Op, Expr> { }; // For unary member operators, determining the return type the normal way can // lead to cyclic dependencies. See FLINTXX_DEFINE_MEMBER_UNOP_RTYPE. template<class Ret, class Op, class Expr> struct unary_op_helper_with_rettype { typedef mp::make_tuple<typename storage_traits<Expr>::type> maker; typedef typename Ret::template make_helper< Op, typename maker::type>::type return_t; }; // Common helper for implementing comparison operators. template<class Expr1, class Expr2> struct order_op_helper { typedef typename tools::evaluation_helper<Expr1>::type ev1_t; typedef typename tools::evaluation_helper<Expr2>::type ev2_t; typedef tools::symmetric_cmp<ev1_t, ev2_t> scmp; typedef mp::enable_if< mp::and_< traits::is_implemented<scmp>, mp::or_< traits::is_expression<Expr1>, traits::is_expression<Expr2> > >, bool> enable; static int get(const Expr1& e1, const Expr2& e2) { return scmp::get(tools::evaluation_helper<Expr1>::get(e1), tools::evaluation_helper<Expr2>::get(e2)); } }; } // detail template<class Expr> inline typename mp::enable_if<traits::is_expression<Expr>, std::ostream&>::type operator<<(std::ostream& o, const Expr& e) { e.print(o); return o; } template<class Expr1, class Expr2> inline typename mp::enable_if<traits::is_expression<Expr1>, bool>::type operator==(const Expr1& e1, const Expr2& e2) { return e1.equals(e2); } template<class Expr1, class Expr2> inline typename mp::enable_if<mp::and_< mp::not_<traits::is_expression<Expr1> >, traits::is_expression<Expr2> >, bool>::type operator==(const Expr1& e1, const Expr2& e2) { return e2.equals(e1); } template<class Expr1, class Expr2> inline typename mp::enable_if<mp::or_< traits::is_expression<Expr1>, traits::is_expression<Expr2> >, bool>::type operator!=(const Expr1& e1, const Expr2& e2) { return !(e1 == e2); } template<class Expr1, class Expr2> inline typename detail::order_op_helper<Expr1, Expr2>::enable::type operator<(const Expr1& e1, const Expr2& e2) { return detail::order_op_helper<Expr1, Expr2>::get(e1, e2) < 0; } template<class Expr1, class Expr2> inline typename detail::order_op_helper<Expr1, Expr2>::enable::type operator<=(const Expr1& e1, const Expr2& e2) { return detail::order_op_helper<Expr1, Expr2>::get(e1, e2) <= 0; } template<class Expr1, class Expr2> inline typename detail::order_op_helper<Expr1, Expr2>::enable::type operator>(const Expr1& e1, const Expr2& e2) { return detail::order_op_helper<Expr1, Expr2>::get(e1, e2) > 0; } template<class Expr1, class Expr2> inline typename detail::order_op_helper<Expr1, Expr2>::enable::type operator>=(const Expr1& e1, const Expr2& e2) { return detail::order_op_helper<Expr1, Expr2>::get(e1, e2) >= 0; } template<class Expr1, class Expr2> inline typename detail::binary_op_helper< Expr1, operations::plus, Expr2>::enable::type operator+(const Expr1& e1, const Expr2& e2) { return detail::binary_op_helper<Expr1, operations::plus, Expr2>::make(e1, e2); } template<class Expr1, class Expr2> inline typename detail::binary_op_helper< Expr1, operations::minus, Expr2>::enable::type operator-(const Expr1& e1, const Expr2& e2) { return detail::binary_op_helper<Expr1, operations::minus, Expr2>::make(e1, e2); } template<class Expr1, class Expr2> inline typename detail::binary_op_helper< Expr1, operations::times, Expr2>::enable::type operator*(const Expr1& e1, const Expr2& e2) { return detail::binary_op_helper<Expr1, operations::times, Expr2>::make(e1, e2); } template<class Expr1, class Expr2> inline typename detail::binary_op_helper< Expr1, operations::divided_by, Expr2>::enable::type operator/(const Expr1& e1, const Expr2& e2) { return detail::binary_op_helper<Expr1, operations::divided_by, Expr2>::make(e1, e2); } template<class Expr1, class Expr2> inline typename detail::binary_op_helper< Expr1, operations::modulo, Expr2>::enable::type operator%(const Expr1& e1, const Expr2& e2) { return detail::binary_op_helper<Expr1, operations::modulo, Expr2>::make(e1, e2); } template<class Expr1, class Expr2> inline typename detail::binary_op_helper< Expr1, operations::binary_and, Expr2>::enable::type operator&(const Expr1& e1, const Expr2& e2) { return detail::binary_op_helper<Expr1, operations::binary_and, Expr2>::make(e1, e2); } template<class Expr1, class Expr2> inline typename detail::binary_op_helper< Expr1, operations::binary_or, Expr2>::enable::type operator|(const Expr1& e1, const Expr2& e2) { return detail::binary_op_helper<Expr1, operations::binary_or, Expr2>::make(e1, e2); } template<class Expr1, class Expr2> inline typename detail::binary_op_helper< Expr1, operations::binary_xor, Expr2>::enable::type operator^(const Expr1& e1, const Expr2& e2) { return detail::binary_op_helper<Expr1, operations::binary_xor, Expr2>::make(e1, e2); } template<class Expr1, class Expr2> inline typename detail::binary_op_helper< Expr1, operations::shift, Expr2>::enable::type operator<<(const Expr1& e1, const Expr2& e2) { return detail::binary_op_helper<Expr1, operations::shift, Expr2>::make(e1, e2); } template<class Expr1, class Expr2> inline typename detail::binary_op_helper< Expr1, operations::shift, Expr2>::enable::type operator>>(const Expr1& e1, const Expr2& e2) { return detail::binary_op_helper<Expr1, operations::shift, Expr2>::make(e1, -e2); } template<class Expr> inline typename detail::unary_op_helper<operations::negate, Expr>::enable::type operator-(const Expr& e) { return detail::unary_op_helper<operations::negate, Expr>::make(e); } template<class Expr> inline typename detail::unary_op_helper<operations::complement, Expr>::enable::type operator~(const Expr& e) { return detail::unary_op_helper<operations::complement, Expr>::make(e); } template<class Expr1, class Expr2> inline typename mp::enable_if<traits::is_immediate_expr<Expr1>, Expr1&>::type operator+=(Expr1& e1, const Expr2& e2) { e1.set(e1 + e2); return e1; } template<class Expr1, class Expr2> inline typename mp::enable_if<traits::is_immediate_expr<Expr1>, Expr1&>::type operator-=(Expr1& e1, const Expr2& e2) { e1.set(e1 - e2); return e1; } template<class Expr1, class Expr2> inline typename mp::enable_if<traits::is_immediate_expr<Expr1>, Expr1&>::type operator*=(Expr1& e1, const Expr2& e2) { e1.set(e1 * e2); return e1; } template<class Expr1, class Expr2> inline typename mp::enable_if<traits::is_immediate_expr<Expr1>, Expr1&>::type operator/=(Expr1& e1, const Expr2& e2) { e1.set(e1 / e2); return e1; } template<class Expr1, class Expr2> inline typename mp::enable_if<traits::is_immediate_expr<Expr1>, Expr1&>::type operator%=(Expr1& e1, const Expr2& e2) { e1.set(e1 % e2); return e1; } template<class Expr1, class Expr2> inline typename mp::enable_if<traits::is_immediate_expr<Expr1>, Expr1&>::type operator|=(Expr1& e1, const Expr2& e2) { e1.set(e1 | e2); return e1; } template<class Expr1, class Expr2> inline typename mp::enable_if<traits::is_immediate_expr<Expr1>, Expr1&>::type operator&=(Expr1& e1, const Expr2& e2) { e1.set(e1 & e2); return e1; } template<class Expr1, class Expr2> inline typename mp::enable_if<traits::is_immediate_expr<Expr1>, Expr1&>::type operator^=(Expr1& e1, const Expr2& e2) { e1.set(e1 ^ e2); return e1; } // c-style IO template<class T> typename mp::enable_if<traits::is_implemented< rules::cprint<typename T::evaluated_t> >, int>::type print(const T& t) { return t.print(); } template<class T> typename mp::enable_if<traits::is_implemented< rules::cprint<typename T::evaluated_t> >, int>::type print(FILE* f, const T& t) { return t.print(f); } template<class T, class U> typename mp::enable_if<traits::is_implemented< rules::print_pretty<typename T::evaluated_t> >, int>::type print_pretty(const T& t, const U& extra) { return t.print_pretty(extra); } template<class T, class U> typename mp::enable_if<traits::is_implemented< rules::print_pretty<typename T::evaluated_t> >, int>::type print_pretty(FILE* f, const T& t, const U& extra) { return t.print_pretty(extra, f); } template<class T> typename mp::enable_if<traits::is_implemented< rules::print_pretty<typename T::evaluated_t> >, int>::type print_pretty(const T& t) { return t.print_pretty(); } template<class T> typename mp::enable_if<traits::is_implemented< rules::print_pretty<typename T::evaluated_t> >, int>::type print_pretty(FILE* f, const T& t) { return t.print_pretty(f); } template<class T> typename mp::enable_if<traits::is_implemented< rules::read<typename T::evaluated_t> >, int>::type read(T& t) { return t.read(); } template<class T> typename mp::enable_if<traits::is_implemented< rules::read<typename T::evaluated_t> >, int>::type read(FILE* f, T& t) { return t.read(f); } // TODO move to std? template<class Expr1, class Expr2> inline typename mp::enable_if<typename traits::is_implemented< rules::swap<Expr1, Expr2> > >::type swap(Expr1& e1, Expr2& e2) { rules::swap<Expr1, Expr2>::doit(e1, e2); } } // TODO remove this? /* Copyright (C) 2013 Tom Bachmann This file is part of FLINT. FLINT is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See <https://www.gnu.org/licenses/>. */ // This file contains default rule implementations #ifndef CXX_DEFAULT_RULES_H #define CXX_DEFAULT_RULES_H namespace flint { namespace rules { // Composite binary operators // These rules implement binary operators by implementing both arguments // separately, then performing the operation on the evaluated types by // instantiating the appropriate rule again. // // Hence to evaluate expressions like a + (b + c), it suffices to write // rules for composition of two immediates. namespace rdetail { template<class Op, class Args> struct can_evaluate_tuple : traits::is_implemented< typename mp::find_evaluation<Op, typename tools::evaluated_args_tuple<Args>::type, true>::type> { }; template<class Op, class Args, class Enable = void> struct should_evaluate_tuple : can_evaluate_tuple<Op, Args> { }; template<class Op, class Args> struct should_evaluate_tuple<Op, Args, typename mp::disable_if<tools::count_nonimm<Args> >::type> : mp::false_ { }; template<class Op, class Data1, class Data2> struct binary_should_enable { typedef mp::enable_if<should_evaluate_tuple< Op, typename mp::make_tuple<Data1, Data2>::type> > enable; }; } template<bool result_is_temporary, class Op, class Data> struct evaluation<Op, Data, result_is_temporary, 0, typename mp::enable_if<rdetail::should_evaluate_tuple<Op, Data> >::type> { typedef tools::evaluate_n<Data> evn_t; typedef typename evn_t::evtup_t evtup_t; typedef typename evn_t::temporaries_t temporaries_t; typedef typename mp::find_evaluation< Op, evtup_t, result_is_temporary>::type rule_t; typedef typename rule_t::return_t return_t; template<class Return> static void doit(const Data& input, temporaries_t temps, Return* output) { evn_t ev(input, temps); rule_t::doit(ev.gettuple(), empty_tuple(), output); } }; // Automatically invoke binary_expression or commutative_binary_expression namespace rdetail { template<class Expr1, class Op, class Expr2, class Enable = void> struct inverted_binary_expression { typedef commutative_binary_expression<Expr2, Op, Expr1> wrapped_t; typedef typename wrapped_t::return_t return_t; template<class Return> static void doit(Return& to, const Expr1& e1, const Expr2& e2) { return wrapped_t::doit(to, e2, e1); } }; template<template<class E1, class O, class E2, class En> class BE, class Data1, class Op, class Data2> struct binary_expr_helper { typedef typename traits::basetype<Data1>::type data1_t; typedef typename traits::basetype<Data2>::type data2_t; typedef BE<data1_t, Op, data2_t, void> wrapped_t; typedef typename wrapped_t::return_t return_t; typedef empty_tuple temporaries_t; typedef typename mp::make_tuple<Data1, Data2>::type data_t; template<class Return> static void doit(const data_t& input, temporaries_t temps, Return* output) { wrapped_t::doit(*output, input.first(), input.second()); } }; } // rdetail template<bool result_is_temporary, class Op, class Data1, class Data2> struct evaluation< Op, tuple<Data1, tuple<Data2, empty_tuple> >, result_is_temporary, 0, typename mp::enable_if< mp::and_< traits::is_immediate<typename traits::basetype<Data1>::type>, mp::and_< traits::is_immediate<typename traits::basetype<Data2>::type>, mp::or_< traits::is_implemented<binary_expression< typename traits::basetype<Data1>::type, Op, typename traits::basetype<Data2>::type > >, mp::or_< traits::is_implemented<commutative_binary_expression< typename traits::basetype<Data1>::type, Op, typename traits::basetype<Data2>::type > >, traits::is_implemented<commutative_binary_expression< typename traits::basetype<Data2>::type, Op, typename traits::basetype<Data1>::type > > > > > > >::type> : mp::if_< traits::is_implemented<binary_expression< typename traits::basetype<Data1>::type, Op, typename traits::basetype<Data2>::type > >, rdetail::binary_expr_helper<binary_expression, Data1, Op, Data2>, typename mp::if_< traits::is_implemented<commutative_binary_expression< typename traits::basetype<Data1>::type, Op, typename traits::basetype<Data2>::type > >, rdetail::binary_expr_helper< commutative_binary_expression, Data1, Op, Data2>, rdetail::binary_expr_helper< rdetail::inverted_binary_expression, Data1, Op, Data2> >::type >::type { }; // Automatically invoke unary_expression template<bool result_is_temporary, class Op, class Data> struct evaluation<Op, tuple<Data, empty_tuple>, result_is_temporary, 0, typename mp::enable_if< traits::is_implemented< unary_expression<Op, typename traits::basetype<Data>::type> > >::type> { typedef unary_expression<Op, typename traits::basetype<Data>::type> wrapped_t; typedef typename wrapped_t::return_t return_t; typedef empty_tuple temporaries_t; typedef typename mp::make_tuple<Data>::type data_t; template<class Return> static void doit(const data_t& input, temporaries_t temps, Return* output) { wrapped_t::doit(*output, input.head); } }; // Automatically invoke threeary_expression template<bool result_is_temporary, class Op, class Data1, class Data2, class Data3> struct evaluation<Op, tuple<Data1, tuple<Data2, tuple<Data3, empty_tuple> > >, result_is_temporary, 0, typename mp::enable_if< traits::is_implemented< threeary_expression<Op, typename traits::basetype<Data1>::type, typename traits::basetype<Data2>::type, typename traits::basetype<Data3>::type> > >::type> { typedef threeary_expression<Op, typename traits::basetype<Data1>::type, typename traits::basetype<Data2>::type, typename traits::basetype<Data3>::type> wrapped_t; typedef typename wrapped_t::return_t return_t; typedef empty_tuple temporaries_t; typedef typename mp::make_tuple<Data1, Data2, Data3>::type data_t; template<class Return> static void doit(const data_t& input, temporaries_t temps, Return* output) { wrapped_t::doit(*output, mp::tuple_get<data_t, 0>::get(input), mp::tuple_get<data_t, 1>::get(input), mp::tuple_get<data_t, 2>::get(input)); } }; // Automatically invoke fourary_expression template<bool result_is_temporary, class Op, class Data1, class Data2, class Data3, class Data4> struct evaluation<Op, tuple<Data1, tuple<Data2, tuple<Data3, tuple<Data4, empty_tuple> > > >, result_is_temporary, 0, typename mp::enable_if< traits::is_implemented< fourary_expression<Op, typename traits::basetype<Data1>::type, typename traits::basetype<Data2>::type, typename traits::basetype<Data3>::type, typename traits::basetype<Data4>::type> > >::type> { typedef fourary_expression<Op, typename traits::basetype<Data1>::type, typename traits::basetype<Data2>::type, typename traits::basetype<Data3>::type, typename traits::basetype<Data4>::type> wrapped_t; typedef typename wrapped_t::return_t return_t; typedef empty_tuple temporaries_t; typedef typename mp::make_tuple<Data1, Data2, Data3, Data4>::type data_t; template<class Return> static void doit(const data_t& input, temporaries_t temps, Return* output) { wrapped_t::doit(*output, mp::tuple_get<data_t, 0>::get(input), mp::tuple_get<data_t, 1>::get(input), mp::tuple_get<data_t, 2>::get(input), mp::tuple_get<data_t, 3>::get(input)); } }; // Automatically invoke fiveary_expression template<bool result_is_temporary, class Op, class Data1, class Data2, class Data3, class Data4, class Data5> struct evaluation<Op, tuple<Data1, tuple<Data2, tuple<Data3, tuple<Data4, tuple<Data5, empty_tuple> > > > >, result_is_temporary, 0, typename mp::enable_if< traits::is_implemented< fiveary_expression<Op, typename traits::basetype<Data1>::type, typename traits::basetype<Data2>::type, typename traits::basetype<Data3>::type, typename traits::basetype<Data4>::type, typename traits::basetype<Data5>::type> > >::type> { typedef fiveary_expression<Op, typename traits::basetype<Data1>::type, typename traits::basetype<Data2>::type, typename traits::basetype<Data3>::type, typename traits::basetype<Data4>::type, typename traits::basetype<Data5>::type> wrapped_t; typedef typename wrapped_t::return_t return_t; typedef empty_tuple temporaries_t; typedef typename mp::make_tuple<Data1, Data2, Data3, Data4, Data5>::type data_t; template<class Return> static void doit(const data_t& input, temporaries_t temps, Return* output) { wrapped_t::doit(*output, mp::tuple_get<data_t, 0>::get(input), mp::tuple_get<data_t, 1>::get(input), mp::tuple_get<data_t, 2>::get(input), mp::tuple_get<data_t, 3>::get(input), mp::tuple_get<data_t, 4>::get(input)); } }; // Automatically invoke sixary_expression template<bool result_is_temporary, class Op, class Data1, class Data2, class Data3, class Data4, class Data5, class Data6> struct evaluation<Op, tuple<Data1, tuple<Data2, tuple<Data3, tuple<Data4, tuple<Data5, tuple<Data6, empty_tuple> > > > > >, result_is_temporary, 0, typename mp::enable_if< traits::is_implemented< sixary_expression<Op, typename traits::basetype<Data1>::type, typename traits::basetype<Data2>::type, typename traits::basetype<Data3>::type, typename traits::basetype<Data4>::type, typename traits::basetype<Data5>::type, typename traits::basetype<Data6>::type> > >::type> { typedef sixary_expression<Op, typename traits::basetype<Data1>::type, typename traits::basetype<Data2>::type, typename traits::basetype<Data3>::type, typename traits::basetype<Data4>::type, typename traits::basetype<Data5>::type, typename traits::basetype<Data6>::type> wrapped_t; typedef typename wrapped_t::return_t return_t; typedef empty_tuple temporaries_t; typedef typename mp::make_tuple<Data1, Data2, Data3, Data4, Data5, Data6>::type data_t; template<class Return> static void doit(const data_t& input, temporaries_t temps, Return* output) { wrapped_t::doit(*output, mp::tuple_get<data_t, 0>::get(input), mp::tuple_get<data_t, 1>::get(input), mp::tuple_get<data_t, 2>::get(input), mp::tuple_get<data_t, 3>::get(input), mp::tuple_get<data_t, 4>::get(input), mp::tuple_get<data_t, 5>::get(input)); } }; // Automatically invoke sevenary_expression template<bool result_is_temporary, class Op, class Data1, class Data2, class Data3, class Data4, class Data5, class Data6, class Data7> struct evaluation<Op, tuple<Data1, tuple<Data2, tuple<Data3, tuple<Data4, tuple<Data5, tuple<Data6, tuple<Data7, empty_tuple> > > > > > >, result_is_temporary, 0, typename mp::enable_if< traits::is_implemented< sevenary_expression<Op, typename traits::basetype<Data1>::type, typename traits::basetype<Data2>::type, typename traits::basetype<Data3>::type, typename traits::basetype<Data4>::type, typename traits::basetype<Data5>::type, typename traits::basetype<Data6>::type, typename traits::basetype<Data7>::type> > >::type> { typedef sevenary_expression<Op, typename traits::basetype<Data1>::type, typename traits::basetype<Data2>::type, typename traits::basetype<Data3>::type, typename traits::basetype<Data4>::type, typename traits::basetype<Data5>::type, typename traits::basetype<Data6>::type, typename traits::basetype<Data7>::type> wrapped_t; typedef typename wrapped_t::return_t return_t; typedef empty_tuple temporaries_t; typedef typename mp::make_tuple<Data1, Data2, Data3, Data4, Data5, Data6, Data7>::type data_t; template<class Return> static void doit(const data_t& input, temporaries_t temps, Return* output) { wrapped_t::doit(*output, mp::tuple_get<data_t, 0>::get(input), mp::tuple_get<data_t, 1>::get(input), mp::tuple_get<data_t, 2>::get(input), mp::tuple_get<data_t, 3>::get(input), mp::tuple_get<data_t, 4>::get(input), mp::tuple_get<data_t, 5>::get(input), mp::tuple_get<data_t, 6>::get(input)); } }; // Instantiating temporaries namespace rdetail { template<class T> struct evaluated_type_pred { template<class Expr> struct type : mp::equal_types< typename tools::evaluation_helper<Expr>::type, T> { }; }; } template<class Expr, class T> struct use_default_temporary_instantiation : mp::true_ { }; template<class Expr, class T, class Enable> struct instantiate_temporaries { static T get(const Expr& e) { return T(); } }; template<class Expr, class T> struct instantiate_temporaries<Expr, T, typename mp::enable_if<mp::and_< use_default_temporary_instantiation<Expr, T>, traits::is_expression<T>, tools::has_subexpr<rdetail::evaluated_type_pred<T>, Expr> > >::type> { static T get(const Expr& e) { return tools::find_subexpr<rdetail::evaluated_type_pred<T> >(e) .create_temporary(); } }; } // rules } // flint #endif //////////////////////////////////////////////////////////////////////// // HELPER MACROS //////////////////////////////////////////////////////////////////////// // To be called in any namespace // Make the binary operation "name" available in current namespace #define FLINT_DEFINE_BINOP_HERE(name) \ template<class T1, class T2> \ inline typename ::flint::detail::binary_op_helper<\ T1, ::flint::operations::name##_op, T2>::enable::type \ name(const T1& t1, const T2& t2) \ { \ return ::flint::detail::binary_op_helper< \ T1, ::flint::operations::name##_op, T2>::make(t1, t2); \ } // Make the unary operation "name" available in current namespace #define FLINT_DEFINE_UNOP_HERE(name) \ template<class T1> \ inline typename ::flint::detail::unary_op_helper<\ ::flint::operations::name##_op, T1>::enable::type \ name(const T1& t1) \ { \ return ::flint::detail::unary_op_helper< ::flint::operations::name##_op, T1>::make(t1); \ } // Make the threeary operation "name" available in current namespace #define FLINT_DEFINE_THREEARY_HERE(name) \ template<class T1, class T2, class T3> \ inline typename ::flint::detail::nary_op_helper2<\ ::flint::operations::name##_op, T1, T2, T3>::enable::type \ name(const T1& t1, const T2& t2, const T3& t3) \ { \ return ::flint::detail::nary_op_helper2< \ ::flint::operations::name##_op, T1, T2, T3>::make(t1, t2, t3); \ } // Make the threeary operation "name" available in current namespace, // but with only two arguments, the second of which is of type type1 and // defaults to val1, and the third argument always (implicitly) of type type2 // and value val2. // The suggested usage of this macro is to first call FLINT_DEFINE_THREEARY_HERE, // and then call FLINT_DEFINE_THREEARY_HERE_2DEFAULT. The effect will be an // operation which can be invoked with 1, 2 or 3 arguments. #define FLINT_DEFINE_THREEARY_HERE_2DEFAULT(name, type1, val1, type2, val2) \ template<class T1> \ inline typename ::flint::detail::nary_op_helper2<\ ::flint::operations::name##_op, T1, type1, type2 >::enable::type \ name(const T1& t1, type1 t2 = val1) \ { \ return ::flint::detail::nary_op_helper2< \ ::flint::operations::name##_op, T1, type1, type2>::make(t1, t2, val2); \ } // Make the fourary operation "name" available in current namespace #define FLINT_DEFINE_FOURARY_HERE(name) \ template<class T1, class T2, class T3, class T4> \ inline typename ::flint::detail::nary_op_helper2<\ ::flint::operations::name##_op, T1, T2, T3, T4>::enable::type \ name(const T1& t1, const T2& t2, const T3& t3, const T4& t4) \ { \ return ::flint::detail::nary_op_helper2< \ ::flint::operations::name##_op, T1, T2, T3, T4>::make(t1, t2, t3, t4); \ } // Make the fiveary operation "name" available in current namespace #define FLINT_DEFINE_FIVEARY_HERE(name) \ template<class T1, class T2, class T3, class T4, class T5> \ inline typename ::flint::detail::nary_op_helper2<\ ::flint::operations::name##_op, T1, T2, T3, T4, T5>::enable::type \ name(const T1& t1, const T2& t2, const T3& t3, const T4& t4, const T5& t5) \ { \ return ::flint::detail::nary_op_helper2< \ ::flint::operations::name##_op, T1, T2, T3, T4, T5>::make(t1, t2, t3, t4, t5); \ } // Make the sixary operation "name" available in current namespace #define FLINT_DEFINE_SIXARY_HERE(name) \ template<class T1, class T2, class T3, class T4, class T5, class T6> \ inline typename ::flint::detail::nary_op_helper2<\ ::flint::operations::name##_op, T1, T2, T3, T4, T5, T6>::enable::type \ name(const T1& t1, const T2& t2, const T3& t3, const T4& t4, const T5& t5, const T6& t6) \ { \ return ::flint::detail::nary_op_helper2< \ ::flint::operations::name##_op, T1, T2, T3, T4, T5, T6>::make(t1, t2, t3, t4, t5, t6); \ } // Make the sevenary operation "name" available in current namespace #define FLINT_DEFINE_SEVENARY_HERE(name) \ template<class T1, class T2, class T3, class T4, class T5, class T6, class T7> \ inline typename ::flint::detail::nary_op_helper2<\ ::flint::operations::name##_op, T1, T2, T3, T4, T5, T6, T7>::enable::type \ name(const T1& t1, const T2& t2, const T3& t3, const T4& t4, const T5& t5, const T6& t6, const T7& t7) \ { \ return ::flint::detail::nary_op_helper2< \ ::flint::operations::name##_op, T1, T2, T3, T4, T5, T6, T7>::make(t1, t2, t3, t4, t5, t6, t7); \ } // This set of macros should be called in namespace flint. // Introduce a new binary operation called "name" // NB: because of ADL bugs in g++ <= 4.4, the operation tag is called "name_op", // whereas the function corresponding to it is just called "name" #define FLINT_DEFINE_BINOP(name) \ namespace operations { \ struct name##_op { }; \ } \ FLINT_DEFINE_BINOP_HERE(name) // This macro can be used to conditionally enable a function, and is mostly // used for forwarding. // A typical usage is // template<class T, class U> // FLINT_BINOP_ENABLE_RETTYPE(myop, T, U) myop_other(const T& t, const U& u) // { // // perhaps something more interesting // return myop(t, u); // } #define FLINT_BINOP_ENABLE_RETTYPE(name, T1, T2) \ typename detail::binary_op_helper<T1, operations::name##_op, T2>::enable::type // Introduce a new unary operation called "name" #define FLINT_DEFINE_UNOP(name) \ namespace operations { \ struct name##_op { }; \ } \ FLINT_DEFINE_UNOP_HERE(name) #define FLINT_UNOP_ENABLE_RETTYPE(name, T) \ typename detail::unary_op_helper<operations::name##_op, T>::return_t // See FLINTXX_DEFINE_MEMBER_UNOP_RTYPE #define FLINT_UNOP_BUILD_RETTYPE(name, rettype, T) \ typename detail::unary_op_helper_with_rettype<rettype, \ operations::name##_op, T>::return_t #define FLINT_DEFINE_THREEARY(name) \ namespace operations { \ struct name##_op { }; \ } \ FLINT_DEFINE_THREEARY_HERE(name) #define FLINT_THREEARY_ENABLE_RETTYPE(name, T1, T2, T3) \ typename detail::nary_op_helper2<operations::name##_op, T1, T2, T3>::enable::type #define FLINT_DEFINE_FOURARY(name) \ namespace operations { \ struct name##_op { }; \ } \ FLINT_DEFINE_FOURARY_HERE(name) #define FLINT_FOURARY_ENABLE_RETTYPE(name, T1, T2, T3, T4) \ typename detail::nary_op_helper2<operations::name##_op, T1, T2, T3, T4>::enable::type #define FLINT_DEFINE_FIVEARY(name) \ namespace operations { \ struct name##_op { }; \ } \ FLINT_DEFINE_FIVEARY_HERE(name) #define FLINT_FIVEARY_ENABLE_RETTYPE(name, T1, T2, T3, T4, T5) \ typename detail::nary_op_helper2<operations::name##_op, T1, T2, T3, T4, T5>::enable::type #define FLINT_DEFINE_SIXARY(name) \ namespace operations { \ struct name##_op { }; \ } \ FLINT_DEFINE_SIXARY_HERE(name) #define FLINT_DEFINE_SEVENARY(name) \ namespace operations { \ struct name##_op { }; \ } \ FLINT_DEFINE_SEVENARY_HERE(name) #endif /* Copyright (C) 2013 Tom Bachmann This file is part of FLINT. FLINT is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See <https://www.gnu.org/licenses/>. */ // Helpers to define concrete subclasses of expression. // Contrary to other parts of this library, they are tailored very // specifically towards FLINT. #ifndef CXX_FLINT_CLASSES_H #define CXX_FLINT_CLASSES_H // Flint classes distinguish themselves from "ordinary" expression template // classes by a public typedef IS_FLINT_CLASS (see also FLINTXX_DEFINE_BASICS // below). Most functionality in this header disables itself when used on a // non-flint class. // For all flint classes, Data of immediates must have typedefs data_ref_t and // data_srcref_t. // The immediates of any flint class come in three "flavours": ordinary, ref // and srcref. Most of the classes below are used to convert these flavours. // In order for this to work, the expression template class must contain a // public typedef c_base_t which is the underlying "basic" C type (so not the // length one array that is usually used), e.g. fmpz_poly_struct. Conversion to // reference type then yields expression templates which have Data set to // ref_data<Wrapped, c_base_t> or srcref_data. These implementation work as // long as all data is stored in c_base_t. If not (e.g. for padic, where there // is an additional reference to the context), ref_data and srcref_data have to // be specialised appropriately. namespace flint { namespace flint_classes { template<class Wrapped, class Inner> struct ref_data { typedef void IS_REF_OR_CREF; typedef Wrapped wrapped_t; typedef Inner* data_ref_t; typedef const Inner* data_srcref_t; Inner* inner; ref_data(Wrapped& o) : inner(o._data().inner) {} static ref_data make(Inner* f) {return ref_data(f);} private: ref_data(Inner* fp) : inner(fp) {} }; template<class Wrapped, class Ref, class Inner> struct srcref_data { typedef void IS_REF_OR_CREF; typedef Wrapped wrapped_t; typedef const Inner* data_ref_t; typedef const Inner* data_srcref_t; const Inner* inner; srcref_data(const Wrapped& o) : inner(o._data().inner) {} srcref_data(Ref o) : inner(o._data().inner) {} static srcref_data make(const Inner* f) {return srcref_data(f);} private: srcref_data(const Inner* fp) : inner(fp) {} }; // Helper to determine if T is a flint class. template<class T, class Enable = void> struct is_flint_class : mp::false_ { }; template<class T> struct is_flint_class<T, typename T::IS_FLINT_CLASS> : mp::true_ { }; // From a lazy or immediate flint expression, obtain the evaluated // non-reference type. // Examples: fmpzxx -> fmpzxx // fmpzxx_ref -> fmpzxx // fmpzxx + fmpzxx -> fmpzxx template<class T, class Enable = void> struct to_nonref {typedef typename T::evaluated_t type;}; template<class T> struct to_nonref<T, typename T::data_t::IS_REF_OR_CREF> { typedef typename T::data_t::wrapped_t type; }; template<class T> struct c_base_t { typedef typename T::c_base_t type; }; // Given a lazy or non-lazy flint expression, obtain th evaluated reference // type. // Examples: fmpzxx -> fmpzxx_ref // fmpzxx_ref -> fmpzxx_ref // fmpzxx + fmpzxx -> fmpzxx_ref template<class T> struct to_ref { typedef typename T::template make_helper<operations::immediate, ref_data< typename to_nonref<T>::type, typename c_base_t<T>::type> >::type type; }; // Similarly for srcref. template<class T> struct to_srcref { typedef typename T::template make_helper<operations::immediate, srcref_data< typename to_nonref<T>::type, typename to_ref<T>::type, typename c_base_t<T>::type> >::type type; }; // Compute if Ref if the reference type belonging to compare. // Examples: fmpzxx_ref, fmpzxx + fmpzxx -> true_ // fmpzxx_srcref, fmpzxx -> false_ template<class Compare, class Ref> struct is_ref : mp::equal_types<Ref, typename to_ref<Compare>::type> { }; // Similarly for srcref. template<class Compare, class Ref> struct is_srcref : mp::equal_types<Ref, typename to_srcref<Compare>::type> { }; // Similarly for non-ref. template<class T> struct is_nonref : mp::equal_types<T, typename to_nonref<T>::type > { }; // Flint classes allow implicit conversion only in very special situations. // This template determines when. Currently, it is used exclusively to allow // implicit conversion to reference types. template<class T, class U, class Enable = void> struct enableimplicit : mp::false_ { }; template<class T, class U> struct enableimplicit<T, U, typename mp::enable_if<mp::and_< is_flint_class<T>, is_flint_class<U> > >::type> : mp::and_< traits::is_immediate_expr<T>, traits::is_immediate_expr<U>, mp::or_< mp::and_<is_ref<U, T>, is_nonref<U> >, mp::and_<is_srcref<U, T>, is_nonref<U> >, mp::and_<is_srcref<U, T>, is_ref<U, U> > > > { }; // Helper template which allows accessing data_(src)ref_t on immediates, // without causing a compiler error on non-immediates. // The main use for this are the _fmpz(), _fmpq() etc methods, which only // work on immediates (but are defined on all instances). template<class Expr, class Enable = void> struct maybe_data_ref { typedef void data_ref_t; typedef void data_srcref_t; }; template<class Expr> struct maybe_data_ref<Expr, typename mp::enable_if< // NB: cannot use is_immediate, since Expr may be incomplete type! mp::equal_types<typename Expr::operation_t, operations::immediate> >::type> { typedef typename Expr::data_t::data_ref_t data_ref_t; typedef typename Expr::data_t::data_srcref_t data_srcref_t; }; // If Base is a non-ref flint class, determine if T is a source operand // (i.e. non-ref, ref or srcref type belong to Base) // Examples: fmpzxx, fmpzxx_srcref -> true // fmpzxx, fmpzxx -> true // fmpzxx, fmpqxx -> false template<class Base, class T, class Enable = void> struct is_source : mp::false_ { }; template<class Base, class T> struct is_source<Base, T, typename mp::enable_if< mp::and_<is_flint_class<T>, is_flint_class<Base> > >::type> : mp::or_<mp::equal_types<T, Base>, is_ref<Base, T>, is_srcref<Base, T> > { }; // Same with target (i.e. disallow srcref). template<class Base, class T, class Enable = void> struct is_target : mp::false_ { }; template<class Base, class T> struct is_target<Base, T, typename mp::enable_if< mp::and_<is_flint_class<T>, is_flint_class<Base> > >::type> : mp::or_<mp::equal_types<T, Base>, is_ref<Base, T> > { }; // Predicate version of the above. Useful for FLINT_DEFINE_*_COND. // See FLINTXX_COND_S and FLINTXX_COND_T template<class Base> struct is_source_base { template<class T> struct type : is_source<Base, T> { }; }; template<class Base> struct is_target_base { template<class T> struct type : is_target<Base, T> { }; }; // Helper for implementing x += y*z etc template<class T, class Right1, class Right2> struct ternary_assign_helper { typedef typename mp::make_tuple<Right1, Right2>::type tup_t; typedef tools::evaluate_n<tup_t> ev2_t; typedef typename ev2_t::temporaries_t temporaries_t; typedef mp::back_tuple<temporaries_t> back_t; typename back_t::type backing; ev2_t ev2; static temporaries_t backtemps(typename back_t::type& backing) { temporaries_t temps; back_t::init(temps, backing); return temps; } ternary_assign_helper(const tup_t& tup) : backing(mp::htuples::fill<typename back_t::type>( tools::temporaries_filler( tup.first()+tup.second() /* XXX */))), ev2(tup, backtemps(backing)) {} const T& getleft() {return ev2.template get<0>();} const T& getright() {return ev2.template get<1>();} }; template<class T, class Right1, class Right2> struct enable_ternary_assign : mp::enable_if<mp::and_< traits::is_T_expr<typename traits::basetype<Right1>::type, T>, traits::is_T_expr<typename traits::basetype<Right2>::type, T> >, T&> { }; // convenience helper template<class Base, class T> struct is_Base : mp::or_< traits::is_T_expr<T, Base>, is_source<Base, T> > { }; } // flint_classes namespace traits { // Enable evaluation into reference types. See can_evaluate_into in // expression_traits.h. // XXX why do we need to disable the case where T, U are equal? // Is <T, T> not more special? template<class T, class U> struct can_evaluate_into<T, U, typename mp::enable_if<mp::and_<flint_classes::is_flint_class<T>, flint_classes::is_flint_class<U>, mp::not_<mp::equal_types<T, U> > > >::type> : flint_classes::is_ref<U, T> { }; } // traits namespace detail { template<class Expr, class Enable = void> struct should_enable_extra_ternop : mp::false_ { }; template<class Expr> struct should_enable_extra_ternop<Expr, typename mp::enable_if< flint_classes::is_flint_class<Expr> >::type> : mp::equal_types<Expr, typename flint_classes::to_ref< typename flint_classes::to_nonref<Expr>::type>::type> { }; } // detail // We add additional overloads for when the LHS is a reference type. The // problem is that the standard overloads take LHS via reference, and rvalues // (such as coming from fmpz_polyxx::get_coeff()) // cannot bind to this. In this case instead objects should be taken by value. // However, this will make the overload ambiguous. Hence we take by const // reference and then make an additional copy. template<class Expr1, class Expr2> inline typename mp::enable_if<detail::should_enable_extra_ternop<Expr1>, Expr1>::type operator+=(const Expr1& e1, const Expr2& e2) { Expr1(e1).set(e1 + e2); return e1; } template<class Expr1, class Expr2> inline typename mp::enable_if<detail::should_enable_extra_ternop<Expr1>, Expr1>::type operator-=(const Expr1& e1, const Expr2& e2) { Expr1(e1).set(e1 - e2); return e1; } template<class Expr1, class Expr2> inline typename mp::enable_if<detail::should_enable_extra_ternop<Expr1>, Expr1>::type operator*=(const Expr1& e1, const Expr2& e2) { Expr1(e1).set(e1 * e2); return e1; } template<class Expr1, class Expr2> inline typename mp::enable_if<detail::should_enable_extra_ternop<Expr1>, Expr1>::type operator/=(const Expr1& e1, const Expr2& e2) { Expr1(e1).set(e1 / e2); return e1; } template<class Expr1, class Expr2> inline typename mp::enable_if<detail::should_enable_extra_ternop<Expr1>, Expr1>::type operator%=(const Expr1& e1, const Expr2& e2) { Expr1(e1).set(e1 % e2); return e1; } template<class Expr1, class Expr2> inline typename mp::enable_if<detail::should_enable_extra_ternop<Expr1>, Expr1>::type operator<<=(const Expr1& e1, const Expr2& e2) { Expr1(e1).set(e1 << e2); return e1; } template<class Expr1, class Expr2> inline typename mp::enable_if<detail::should_enable_extra_ternop<Expr1>, Expr1>::type operator>>=(const Expr1& e1, const Expr2& e2) { Expr1(e1).set(e1 >> e2); return e1; } } // flint // macros that help defining flint classes #define FLINTXX_DEFINE_BASICS_NOFLINTCLASS(name) \ public: \ typedef typename base_t::evaluated_t evaluated_t; \ \ template<class T> \ struct doimplicit \ : flint_classes::enableimplicit<name, T> { }; \ \ template<class T> \ name& operator=(const T& t) \ { \ this->set(t); \ return *this; \ } \ \ protected: \ explicit name(const Data& d) : base_t(d) {} \ \ template<class D, class O, class Da> \ friend class expression; // all flint classes should have this #define FLINTXX_DEFINE_BASICS(name) \ public: \ typedef void IS_FLINT_CLASS; \ FLINTXX_DEFINE_BASICS_NOFLINTCLASS(name) \ // all flint classes should have this #define FLINTXX_DEFINE_CTORS(name) \ public: \ name() : base_t() {} \ template<class T> \ explicit name(const T& t, \ typename mp::disable_if<doimplicit<T> >::type* = 0) \ : base_t(t) {} \ template<class T> \ explicit name(T& t, \ typename mp::disable_if<doimplicit<T> >::type* = 0) \ : base_t(t) {} \ template<class T> \ name(const T& t, \ typename mp::enable_if<doimplicit<T> >::type* = 0) \ : base_t(t) {} \ template<class T> \ name(T& t, \ typename mp::enable_if<doimplicit<T> >::type* = 0) \ : base_t(t) {} \ template<class T, class U> \ name(const T& t, const U& u) : base_t(t, u) {} \ template<class T, class U> \ name(T& t, const U& u) : base_t(t, u) {} \ template<class T, class U, class V> \ name(const T& t, const U& u, const V& v) : base_t(t, u, v) {} \ template<class T, class U, class V> \ name(T& t, const U& u, const V& v) : base_t(t, u, v) {} \ template<class T, class U, class V, class W> \ name(const T& t, const U& u, const V& v, const W& w) \ : base_t(t, u, v, w) {} \ template<class T, class U, class V, class W> \ name(T& t, const U& u, const V& v, const W& w) \ : base_t(t, u, v, w) {} // Enable the flint reference type scheme. This typedefs c_base_t to ctype, // and adds the data access wrapper (like _fmpz(), _fmpq()) called accessname. // It also provides reference constructors from C types. // All flint classes should have this. #define FLINTXX_DEFINE_C_REF(name, ctype, accessname) \ public: \ typedef ctype c_base_t; \ typedef flint_classes::maybe_data_ref<name> wrapped_traits; \ typename wrapped_traits::data_ref_t accessname() \ { \ return this->_data().inner; \ } \ typename wrapped_traits::data_srcref_t accessname() const \ { \ return this->_data().inner; \ } \ \ /* These only make sense with the reference types */ \ template<class T> \ static name make(T& f) \ { \ return name(Data::make(f)); \ } \ template<class T> \ static name make(const T& f) \ { \ return name(Data::make(f)); \ } \ template<class T, class U> \ static name make(T& f, const U& u) \ { \ return name(Data::make(f, u)); \ } \ template<class T, class U> \ static name make(const T& f, const U& u) \ { \ return name(Data::make(f, u)); \ } \ template<class T, class U, class V> \ static name make(const T& f, const U& u, const V& v) \ { \ return name(Data::make(f, u, v)); \ } // Add a statically forwarded constructor called name. (Forwarded to data_t). #define FLINTXX_DEFINE_FORWARD_STATIC(name) \ template<class T> \ static typename base_t::derived_t name(const T& f) \ { \ return typename base_t::derived_t(Data::name(f)); \ } \ template<class T, class U> \ static typename base_t::derived_t name(const T& f, const U& u) \ { \ return typename base_t::derived_t(Data::name(f, u)); \ } // Add a static randomisation function. // XXX this is not really useful because the arguments are often different. #define FLINTXX_DEFINE_RANDFUNC(CBase, name) \ static CBase##xx_expression name(frandxx& state, flint_bitcnt_t bits) \ { \ CBase##xx_expression res; \ CBase##_##name(res._data().inner, state._data(), bits); \ return res; \ } // Add a forwarded unary operation to the class. Suppose there is a unary // operation foo() which returns my_typeA, and takes an argument of type // my_typeB. Now on instances my_typeB, you want to write x.bar() for foo(x). // Then add FLINTXX_DEFINE_MEMBER_UNOP_RTYPE_(my_typeA, bar, foo) to my_typeB. // // XXX due to circular definition problems, this cannot use the usual // unary_op_helper type approach, and the unop must return the same type // of expression #define FLINTXX_DEFINE_MEMBER_UNOP_RTYPE_(rettype, name, funcname) \ FLINT_UNOP_BUILD_RETTYPE(funcname, rettype, typename base_t::derived_t) \ name() const \ { \ return flint::funcname(*this); \ } // Convenience version when name==funcname #define FLINTXX_DEFINE_MEMBER_UNOP_RTYPE(rettype, name) \ FLINTXX_DEFINE_MEMBER_UNOP_RTYPE_(rettype, name, name) // Convenience version when rettype==argtype #define FLINTXX_DEFINE_MEMBER_UNOP_(name, funcname) \ FLINTXX_DEFINE_MEMBER_UNOP_RTYPE_(typename base_t::derived_t, name, funcname) // Convenience version when rettype==argtype and name==funcname #define FLINTXX_DEFINE_MEMBER_UNOP(name) FLINTXX_DEFINE_MEMBER_UNOP_(name, name) // Add a forwarded binary operation. It is not necessary to specify the return // type. #define FLINTXX_DEFINE_MEMBER_BINOP_(name, funcname) \ template<class T> \ typename detail::binary_op_helper<typename base_t::derived_t, \ operations::funcname##_op, T>::enable::type \ name(const T& t) const \ { \ return flint::funcname(*this, t); \ } // Convenience version when funcname==name. #define FLINTXX_DEFINE_MEMBER_BINOP(name) \ FLINTXX_DEFINE_MEMBER_BINOP_(name, name) #define FLINTXX_DEFINE_MEMBER_3OP_(name, funcname) \ template<class T, class U> \ typename detail::nary_op_helper2<operations::funcname##_op, \ typename base_t::derived_t, T, U>::enable::type \ name(const T& t, const U& u) const \ { \ return flint::funcname(*this, t, u); \ } #define FLINTXX_DEFINE_MEMBER_3OP(name) \ FLINTXX_DEFINE_MEMBER_3OP_(name, name) #define FLINTXX_DEFINE_MEMBER_4OP_(name, funcname) \ template<class T, class U, class V> \ typename detail::nary_op_helper2<operations::funcname##_op, \ typename base_t::derived_t, T, U, V>::enable::type \ name(const T& t, const U& u, const V& v) const \ { \ return flint::funcname(*this, t, u, v); \ } #define FLINTXX_DEFINE_MEMBER_4OP(name) \ FLINTXX_DEFINE_MEMBER_4OP_(name, name) #define FLINTXX_DEFINE_MEMBER_5OP_(name, funcname) \ template<class T, class U, class V, class W> \ typename detail::nary_op_helper2<operations::funcname##_op, \ typename base_t::derived_t, T, U, V, W>::enable::type \ name(const T& t, const U& u, const V& v, const W& w) const \ { \ return flint::funcname(*this, t, u, v, w); \ } #define FLINTXX_DEFINE_MEMBER_5OP(name) \ FLINTXX_DEFINE_MEMBER_5OP_(name, name) // Helper macros for FLINT_DEFINE_*_COND?. #define FLINTXX_COND_S(Base) flint_classes::is_source_base<Base>::template type #define FLINTXX_COND_T(Base) flint_classes::is_target_base<Base>::template type // Convenience rules. These all take a Base class as argument, and will // automatically apply to the related reference types as well. // Add a to_string() conversion rule, empolying the common flint idiom where // the string is allocated by the to_string function. #define FLINTXX_DEFINE_TO_STR(Base, eval) \ template<class T> \ struct to_string<T, \ typename mp::enable_if< FLINTXX_COND_S(Base)<T> >::type> \ { \ static std::string get(const T& from, int base) \ { \ char* str = eval; \ std::string res(str); \ flint_free(str); \ return res; \ } \ }; // Add a swap rule. #define FLINTXX_DEFINE_SWAP(Base, eval) \ template<class T, class U> \ struct swap<T, U, typename mp::enable_if< mp::and_< \ FLINTXX_COND_T(Base)<T>, FLINTXX_COND_T(Base)<U> > >::type> \ { \ static void doit(T& e1, U& e2) \ { \ eval; \ } \ }; // Define a conversion rule through a default-constructed temporary object. #define FLINTXX_DEFINE_CONVERSION_TMP(totype, Base, eval) \ template<class T> \ struct conversion<totype, T, \ typename mp::enable_if< FLINTXX_COND_S(Base)<T> >::type> \ { \ static totype get(const T& from) \ { \ totype to; \ eval; \ return to; \ } \ }; // Define a cmp rule. #define FLINTXX_DEFINE_CMP(Base, eval) \ template<class T, class U> \ struct cmp<T, U, \ typename mp::enable_if<mp::and_<FLINTXX_COND_S(Base)<T>, \ FLINTXX_COND_S(Base)<U> > >::type> \ { \ static int get(const T& e1, const U& e2) \ { \ return eval; \ } \ }; // Define an equals rule. #define FLINTXX_DEFINE_EQUALS(Base, eval) \ template<class T, class U> \ struct equals<T, U, typename mp::enable_if<mp::and_< \ FLINTXX_COND_S(Base)<T>, FLINTXX_COND_S(Base)<U> > >::type> \ { \ static bool get(const T& e1, const U& e2) \ { \ return eval; \ } \ }; // Define a string assignment rule (c/f many polynomial classes). #define FLINTXX_DEFINE_ASSIGN_STR(Base, eval) \ template<class T, class U> \ struct assignment<T, U, \ typename mp::enable_if<mp::and_< \ FLINTXX_COND_T(Base)<T>, traits::is_string<U> > >::type> \ { \ static void doit(T& to, const char* from) \ { \ eval; \ } \ }; #define FLINTXX_UNADORNED_MAKETYPES(Base, left, op, right) \ Base##_expression< op, tuple< left, tuple< right, empty_tuple> > > // Optimized evaluation rules using ternary arithmetic (addmul, submul) // NB: this has to be called in namespace flint, not flint::rules! #define FLINTXX_DEFINE_TERNARY(Base, addmuleval, submuleval, maketypes) \ namespace rules { \ /* a +- b*c */ \ template<class Op, class Left, class Right1, class Right2> \ struct evaluation<Op, \ tuple<Left, tuple< \ maketypes(Base, Right1, operations::times, Right2), \ /* NB: there is no particular reason to have the enable_if here, \ many other similar places would do */ \ typename mp::enable_if<mp::or_< \ mp::equal_types<Op, operations::plus>, \ mp::equal_types<Op, operations::minus> >, \ empty_tuple>::type> >, \ true, 1, \ typename tools::ternary_helper<Base, Left, Right1, Right2>::enable::type> \ { \ /* Helpful for testing. */ \ static const unsigned TERNARY_OP_MARKER = 0; \ \ typedef Base return_t; \ typedef tools::ternary_helper<Base, Left, Right1, Right2> th; \ typedef typename th::temporaries_t temporaries_t; \ typedef tuple<Left, tuple< \ maketypes(Base, Right1, operations::times, Right2), \ empty_tuple> > data_t; \ static const bool is_add = mp::equal_types<Op, operations::plus>::val; \ \ static void doit(const data_t& input, temporaries_t temps, return_t* res) \ { \ const Base* left = 0; \ const Base* right = 0; \ th::doit(input.first(), input.second()._data().first(), \ input.second()._data().second(), temps, res, right, left); \ const Base& e1 = *left; \ const Base& e2 = *right; \ Base& to = *res; \ if(is_add) \ { \ addmuleval; \ } \ else \ { \ submuleval; \ } \ } \ }; \ \ /* b*c + a */ \ template<class Right, class Left1, class Left2> \ struct evaluation<operations::plus, \ tuple<maketypes(Base, Left1, operations::times, Left2), \ tuple<Right, empty_tuple> >, \ true, 1, \ typename tools::ternary_helper<Base, \ Right, Left1, Left2, operations::times>::enable::type> \ { \ /* Helpful for testing. */ \ static const unsigned TERNARY_OP_MARKER = 0; \ \ typedef Base return_t; \ typedef tools::ternary_helper<Base, Right, Left1, Left2> th; \ typedef typename th::temporaries_t temporaries_t; \ typedef tuple<maketypes(Base, Left1, operations::times, Left2), \ tuple<Right, empty_tuple> > data_t; \ \ static void doit(const data_t& input, temporaries_t temps, return_t* res) \ { \ const Base* left = 0; \ const Base* right = 0; \ th::doit(input.second(), input.first()._data().first(), \ input.first()._data().second(), temps, res, right, left); \ const Base& e1 = *left; \ const Base& e2 = *right; \ Base& to = *res; \ addmuleval; \ } \ }; \ } /* rules */ \ \ /* TODO enable these with references on left hand side(?) */ \ /* a += b*c */ \ template<class Right1, class Right2> \ inline typename flint_classes::enable_ternary_assign<Base, Right1, Right2>::type \ operator+=(Base& to, \ const maketypes(Base, Right1, operations::times, Right2)& other) \ { \ flint_classes::ternary_assign_helper<Base, Right1, Right2> tah( \ other._data()); \ const Base& e1 = tah.getleft(); \ const Base& e2 = tah.getright(); \ addmuleval; \ return to; \ } \ \ /* a -= b*c */ \ template<class Right1, class Right2> \ inline typename flint_classes::enable_ternary_assign<Base, Right1, Right2>::type \ operator-=(Base& to, \ const maketypes(Base, Right1, operations::times, Right2)& other) \ { \ flint_classes::ternary_assign_helper<Base, Right1, Right2> tah( \ other._data()); \ const Base& e1 = tah.getleft(); \ const Base& e2 = tah.getright(); \ submuleval; \ return to; \ } #endif /* Copyright (C) 2013 Tom Bachmann This file is part of FLINT. FLINT is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See <https://www.gnu.org/licenses/>. */ #ifndef CXX_FRANDXX_H #define CXX_FRANDXX_H // This class contains a first-class wrapper of flint_rand_t. // Note that frandxx is not copyable. namespace flint { class frandxx { private: flint_rand_t inner; // not copyable frandxx(const frandxx&); public: frandxx() {flint_randinit(inner);} ~frandxx() {flint_randclear(inner);} flint_rand_t& _data() {return inner;} const flint_rand_t& _data() const {return inner;} }; } // flint #endif /* Copyright (C) 2013 Tom Bachmann This file is part of FLINT. FLINT is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See <https://www.gnu.org/licenses/>. */ // Lazy tuple class (for use in expression templates) // Note that assignment and comparison are performed elementwise, and types // need not match (even for equality) as long as the operations can be performed // on underlying types. #ifndef FLINTXX_LTUPLE_H #define FLINTXX_LTUPLE_H #ifndef FLINT_LTUPLE_PLACEHOLDER_NAME #define FLINT_LTUPLE_PLACEHOLDER_NAME _ #endif namespace flint { // For lazy get<n>, this operation type is created. namespace operations { template<unsigned n> struct ltuple_get_op { }; } // operations namespace detail { // Empty marker type struct INSTANTIATE_FROM_TUPLE { }; // Traits for the ltuple expression template get<> operation. If the ltuple is // an immediate, return references. Else if the return type is an expression // template, return an expression template. Otherwise, evaluate the ltuple and // return a copy of the entry. template<unsigned n, class Underlying, class Operation, class Data, class Expr, class Enable = void> struct ltuple_get_traits { typedef unary_op_helper<operations::ltuple_get_op<n>, Expr> uoh; typedef typename uoh::return_t type; typedef type ctype; static type get(const Expr& e) { return uoh::make(e); } }; template<unsigned n, class Underlying, class Data, class Expr> struct ltuple_get_traits<n, Underlying, operations::immediate, Data, Expr> { typedef mp::tuple_get<Underlying, n> getter; typedef typename getter::type btype; typedef typename traits::forwarding<btype>::type ctype; typedef typename traits::reference<btype>::type type; static type get(Expr& t) { return getter::get(t._data().inner); } static ctype get(const Expr& t) { return getter::get(t._data().inner); } }; template<unsigned n, class Underlying, class Operation, class Data, class Expr> struct ltuple_get_traits<n, Underlying, Operation, Data, Expr, typename mp::enable_if<mp::and_< mp::not_<mp::equal_types<Operation, operations::immediate> >, mp::not_<traits::is_expression<typename mp::tuple_get<Underlying, n>::type> > > >::type> { typedef mp::tuple_get<Underlying, n> getter; typedef typename getter::type type; typedef type ctype; static type get(const Expr& t) { return getter::get(t.evaluate()._data().inner); } }; // Instances of this can be passed to ltuple[ref]() and will be replaced by // temporaries of the right type before assignment. struct IGNORED_TYPE { }; template<class Ltuple, class To, class Enable = void> struct ltuple_instantiate_ignored_types; } // detail // The ltuple expression template class. Underlying is a tuple type. template<class Underlying, class Operation, class Data> class ltuple_expression : public expression<derived_wrapper2<ltuple_expression, Underlying>, Operation, Data> { public: typedef expression<derived_wrapper2< ::flint::ltuple_expression, Underlying>, Operation, Data> base_t; // internal typedef void IS_LTUPLE_EXPRESSION; typedef Underlying underlying_t; ltuple_expression() {} template<class T> ltuple_expression(detail::INSTANTIATE_FROM_TUPLE i, const T& t) : base_t(i, t) {} template<class T> ltuple_expression& operator=(const T& t) { detail::ltuple_instantiate_ignored_types< ltuple_expression, T> inst(*this, t); inst.set(t); return *this; } template<unsigned n> typename detail::ltuple_get_traits<n, Underlying, Operation, Data, ltuple_expression>::type get() { return detail::ltuple_get_traits< n, Underlying, Operation, Data, ltuple_expression>::get(*this); } template<unsigned n> typename detail::ltuple_get_traits<n, Underlying, Operation, Data, ltuple_expression>::ctype get() const { return detail::ltuple_get_traits< n, Underlying, Operation, Data, ltuple_expression>::get(*this); } typename base_t::evaluated_t create_temporary() const { return typename base_t::evaluated_t(detail::INSTANTIATE_FROM_TUPLE(), mp::htuples::fill<underlying_t>(tools::temporaries_filler(*this))); } protected: explicit ltuple_expression(const Data& d) : base_t(d) {} template<class D, class O, class Da> friend class expression; }; namespace detail { template<class Underlying> struct ltuple_data { Underlying inner; ltuple_data() {} template<class T> ltuple_data(INSTANTIATE_FROM_TUPLE, const T& t) : inner(t) {} }; template<class T> struct to_ref : traits::reference<T> { }; template<class T> struct to_srcref : traits::reference<typename traits::make_const<T>::type> { }; template<template<class>class Transform, class Tuple> struct transform_tuple { typedef tuple<typename Transform<typename Tuple::head_t>::type, typename transform_tuple<Transform, typename Tuple::tail_t>::type> type; }; template<template<class>class Transform> struct transform_tuple<Transform, empty_tuple> { typedef empty_tuple type; }; } // detail // Helper for building ltuple types. template<class Underlying> struct make_ltuple { typedef ltuple_expression<Underlying, operations::immediate, detail::ltuple_data<Underlying> > type; typedef typename detail::transform_tuple<detail::to_ref, Underlying>::type Underlying_ref; typedef typename detail::transform_tuple<detail::to_srcref, Underlying>::type Underlying_srcref; typedef ltuple_expression<Underlying_ref, operations::immediate, detail::ltuple_data<Underlying_ref> > ref_type; typedef ltuple_expression<Underlying_srcref, operations::immediate, detail::ltuple_data<Underlying_srcref> > srcref_type; }; namespace traits { template<class Tuple, class Enable = void> struct is_ltuple_expr : mp::false_ { }; template<class Tuple> struct is_ltuple_expr<Tuple, typename Tuple::IS_LTUPLE_EXPRESSION> : mp::true_ { }; // enable evaluation directly into tuple template<class To, class From> struct can_evaluate_into<To, From, typename mp::enable_if<mp::and_<is_ltuple_expr<From>, is_ltuple_expr<To>, mp::not_<mp::equal_types<To, From> > > >::type> : mp::true_ { }; } // traits namespace detail { template<class Ltuple, class To, class Enable> struct ltuple_instantiate_ignored_types { // degenerate case: To is not a tuple Ltuple& saved; ltuple_instantiate_ignored_types(Ltuple& s, const To&) : saved(s) {} void set(const To& to) {saved.set(to);} }; template<class ToTuple, class FromTuple> struct tuple_instantiate_ignored { typedef tuple_instantiate_ignored<typename ToTuple::tail_t, typename FromTuple::tail_t> next_t; typedef typename traits::reference<typename ToTuple::head_t>::type ref_t; typedef tuple<ref_t, typename next_t::type> type; next_t next; ref_t ref; template<class From> tuple_instantiate_ignored(ToTuple& to, const From& from) : next(to.tail, from), ref(to.head) {} type get() { return type(ref, next.get()); } }; template<> struct tuple_instantiate_ignored<empty_tuple, empty_tuple> { typedef empty_tuple type; template<class F> tuple_instantiate_ignored(empty_tuple, const F&) {} empty_tuple get() {return empty_tuple();} }; template<class ToTail, class From, class FromTail> struct tuple_instantiate_ignored< tuple<IGNORED_TYPE&, ToTail>, tuple<From, FromTail> > { typedef tuple_instantiate_ignored<ToTail, FromTail> next_t; typedef typename traits::reference<From>::type ref_t; typedef tuple<ref_t, typename next_t::type> type; next_t next; From tmp; template<class ToTuple, class FromExpr> tuple_instantiate_ignored(ToTuple& to, const FromExpr& from) : next(to.tail, from), tmp(rules::instantiate_temporaries<FromExpr, From>::get(from)) {} type get() { return type(tmp, next.get()); } }; template<class Ltuple, class T> struct ltuple_instantiate_ignored_types<Ltuple, T, typename mp::enable_if<traits::is_ltuple_expr<T> >::type> { typedef tuple_instantiate_ignored< typename Ltuple::underlying_t, typename T::underlying_t> tii_t; tii_t tii; ltuple_instantiate_ignored_types(Ltuple& l, const T& t) : tii(l._data().inner, t) {} void set(const T& t) { typename make_ltuple<typename tii_t::type>::type(INSTANTIATE_FROM_TUPLE(), tii.get()).set(t); } }; } namespace rules { template<class Tuple1, class Tuple2> struct assignment<Tuple1, Tuple2, typename mp::enable_if<mp::and_< traits::is_ltuple_expr<Tuple2>, traits::is_ltuple_expr<Tuple1> > >::type> { static void doit(Tuple1& to, const Tuple2& from) { to._data().inner.set(from._data().inner); } }; template<class Tuple1, class Tuple2> struct equals<Tuple1, Tuple2, typename mp::enable_if<mp::and_< traits::is_ltuple_expr<Tuple2>, traits::is_ltuple_expr<Tuple1> > >::type> { static bool get(const Tuple1& to, const Tuple2& from) { return to._data().inner.equals_elementwise(from._data().inner); } }; template<class Tuple, unsigned n> struct unary_expression<operations::ltuple_get_op<n>, Tuple, typename mp::enable_if<mp::and_< traits::is_ltuple_expr<Tuple>, traits::is_immediate<Tuple> > >::type> { typedef typename mp::tuple_get<typename Tuple::underlying_t, n>::type return_t; template<class R> static void doit(R& to, const Tuple& from) { to = from.template get<n>(); } }; } // rules // TODO we would really like variadic templates / lvalue references here // Helpers to build ltuples from (references to) arguments. template<class T> inline typename make_ltuple<typename mp::make_tuple<T>::type>::type ltuple(const T& t) { return typename make_ltuple<typename mp::make_tuple<T>::type>::type( detail::INSTANTIATE_FROM_TUPLE(), mp::make_tuple<T>::make(t)); } template<class T, class U> inline typename make_ltuple<typename mp::make_tuple<T, U>::type>::type ltuple(const T& t, const U& u) { return typename make_ltuple<typename mp::make_tuple<T, U>::type>::type( detail::INSTANTIATE_FROM_TUPLE(), mp::make_tuple<T, U>::make(t, u)); } template<class T, class U, class V> inline typename make_ltuple<typename mp::make_tuple<T, U, V>::type>::type ltuple(const T& t, const U& u, const V& v) { return typename make_ltuple<typename mp::make_tuple<T, U, V>::type>::type( detail::INSTANTIATE_FROM_TUPLE(), mp::make_tuple<T, U, V>::make(t, u, v)); } template<class T, class U, class V, class W> inline typename make_ltuple<typename mp::make_tuple<T, U, V, W>::type>::type ltuple(const T& t, const U& u, const V& v, const W& w) { return typename make_ltuple<typename mp::make_tuple<T, U, V, W>::type>::type( detail::INSTANTIATE_FROM_TUPLE(), mp::make_tuple<T, U, V, W>::make(t, u, v, w)); } template<class T> inline typename make_ltuple<typename mp::make_tuple<T&>::type>::type ltupleref(T& t) { return typename make_ltuple<typename mp::make_tuple<T&>::type>::type( detail::INSTANTIATE_FROM_TUPLE(), mp::make_tuple<T&>::make(t)); } template<class T, class U> inline typename make_ltuple<typename mp::make_tuple<T&, U&>::type>::type ltupleref(T& t, U& u) { return typename make_ltuple<typename mp::make_tuple<T&, U&>::type>::type( detail::INSTANTIATE_FROM_TUPLE(), mp::make_tuple<T&, U&>::make(t, u)); } template<class T, class U, class V> inline typename make_ltuple<typename mp::make_tuple<T&, U&, V&>::type>::type ltupleref(T& t, U& u, V& v) { return typename make_ltuple<typename mp::make_tuple<T&, U&, V&>::type>::type( detail::INSTANTIATE_FROM_TUPLE(), mp::make_tuple<T&, U&, V&>::make(t, u, v)); } template<class T, class U, class V, class W> inline typename make_ltuple<typename mp::make_tuple<T&, U&, V&, W&>::type>::type ltupleref(T& t, U& u, V& v, W& w) { return typename make_ltuple<typename mp::make_tuple<T&, U&, V&, W&>::type>::type( detail::INSTANTIATE_FROM_TUPLE(), mp::make_tuple<T&, U&, V&, W&>::make(t, u, v, w)); } // static placeholder static detail::IGNORED_TYPE FLINT_LTUPLE_PLACEHOLDER_NAME; namespace detail { void remove_compiler_warning( detail::IGNORED_TYPE* = &FLINT_LTUPLE_PLACEHOLDER_NAME); } // detail } // flint #endif /* Copyright (C) 2013 Tom Bachmann This file is part of FLINT. FLINT is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See <https://www.gnu.org/licenses/>. */ #ifndef FLINT_CXX_STDMATH_H #define FLINT_CXX_STDMATH_H // This file defines lazy operations which are used by several different flint // classes. namespace flint { FLINT_DEFINE_BINOP(pow) FLINT_DEFINE_BINOP(pow_binexp) FLINT_DEFINE_BINOP(root) FLINT_DEFINE_UNOP(abs) FLINT_DEFINE_UNOP(exp) FLINT_DEFINE_UNOP(log) FLINT_DEFINE_UNOP(sqrt) FLINT_DEFINE_UNOP(inv) FLINT_DEFINE_UNOP(sqr) FLINT_DEFINE_UNOP(sqr_classical) FLINT_DEFINE_UNOP(sqr_KS) FLINT_DEFINE_UNOP(height) FLINT_DEFINE_BINOP(divexact) FLINT_DEFINE_BINOP(divrem) FLINT_DEFINE_BINOP(fdiv_2exp) FLINT_DEFINE_BINOP(mul_2exp) FLINT_DEFINE_BINOP(mul_classical) FLINT_DEFINE_BINOP(mul_KS) FLINT_DEFINE_BINOP(tdiv) FLINT_DEFINE_BINOP(tdiv_2exp) FLINT_DEFINE_THREEARY(mulhigh) FLINT_DEFINE_THREEARY(mulhigh_classical) FLINT_DEFINE_THREEARY(mullow) FLINT_DEFINE_THREEARY(mullow_classical) FLINT_DEFINE_THREEARY(mullow_KS) FLINT_DEFINE_BINOP(smod) // "symmetric" % // poly functions FLINT_DEFINE_BINOP(compose) FLINT_DEFINE_BINOP(compose_divconquer) FLINT_DEFINE_BINOP(compose_horner) FLINT_DEFINE_BINOP(div_basecase) FLINT_DEFINE_BINOP(div_divconquer) FLINT_DEFINE_BINOP(divrem_basecase) FLINT_DEFINE_BINOP(divrem_divconquer) FLINT_DEFINE_BINOP(div_root) FLINT_DEFINE_BINOP(evaluate) FLINT_DEFINE_BINOP(bit_pack) FLINT_DEFINE_BINOP(shift_left) FLINT_DEFINE_BINOP(shift_right) FLINT_DEFINE_BINOP(rem_basecase) FLINT_DEFINE_BINOP(resultant) FLINT_DEFINE_BINOP(reverse) FLINT_DEFINE_BINOP(taylor_shift) FLINT_DEFINE_BINOP(taylor_shift_horner) FLINT_DEFINE_UNOP(content) FLINT_DEFINE_UNOP(derivative) FLINT_DEFINE_UNOP(integral) FLINT_DEFINE_UNOP(make_monic) FLINT_DEFINE_UNOP(twonorm) FLINT_DEFINE_UNOP(bound_roots) FLINT_DEFINE_UNOP(primitive_part) FLINT_DEFINE_BINOP(inv_series) FLINT_DEFINE_BINOP(inv_series_newton) FLINT_DEFINE_BINOP(revert_series) FLINT_DEFINE_BINOP(revert_series_lagrange) FLINT_DEFINE_BINOP(revert_series_lagrange_fast) FLINT_DEFINE_BINOP(revert_series_newton) FLINT_DEFINE_BINOP(sqrt_series) FLINT_DEFINE_BINOP(invsqrt_series) FLINT_DEFINE_BINOP(exp_series) FLINT_DEFINE_BINOP(log_series) FLINT_DEFINE_BINOP(atan_series) FLINT_DEFINE_BINOP(atanh_series) FLINT_DEFINE_BINOP(asin_series) FLINT_DEFINE_BINOP(asinh_series) FLINT_DEFINE_BINOP(tan_series) FLINT_DEFINE_BINOP(sin_series) FLINT_DEFINE_BINOP(cos_series) FLINT_DEFINE_BINOP(sinh_series) FLINT_DEFINE_BINOP(cosh_series) FLINT_DEFINE_BINOP(tanh_series) FLINT_DEFINE_THREEARY(compose_series) FLINT_DEFINE_THREEARY(compose_series_brent_kung) FLINT_DEFINE_THREEARY(compose_series_divconquer) FLINT_DEFINE_THREEARY(compose_series_horner) FLINT_DEFINE_THREEARY(div_series) FLINT_DEFINE_THREEARY(pow_trunc) FLINT_DEFINE_THREEARY(pow_trunc_binexp) FLINT_DEFINE_BINOP(compeval) // matrix functions in flintxx/matrix.h // chinese remaindering FLINT_DEFINE_FIVEARY(CRT) FLINT_DEFINE_FOURARY_HERE(CRT) // four argument version FLINT_DEFINE_THREEARY(multi_CRT) FLINT_DEFINE_BINOP_HERE(multi_CRT) // two argument version // implementation of compeval namespace rules { // implementation of compeval // TODO do at level of "struct evaluation" instead? template<class T, class U> struct binary_expression<T, operations::compeval_op, U, typename mp::enable_if<mp::or_< traits::is_implemented<binary_expression<T, operations::compose_op, U> >, traits::is_implemented<binary_expression<T, operations::evaluate_op, U> > > >::type> : mp::if_< traits::is_implemented<binary_expression<T, operations::compose_op, U> >, binary_expression<T, operations::compose_op, U>, binary_expression<T, operations::evaluate_op, U> >::type { }; } // rules } // flint #endif /* Copyright (C) 2009 William Hart This file is part of FLINT. FLINT is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See <https://www.gnu.org/licenses/>. */ #ifndef FMPZ_H #define FMPZ_H #ifdef FMPZ_INLINES_C #define FMPZ_INLINE FLINT_DLL #else #define FMPZ_INLINE static __inline__ #endif #undef ulong #define ulong ulongxx/* interferes with system includes */ #include <stdlib.h> #include <stdio.h> #undef ulong #include <gmp.h> #define ulong mp_limb_t /* Copyright (C) 2010 William Hart Copyright (C) 2021 Fredrik Johansson This file is part of FLINT. FLINT is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See <https://www.gnu.org/licenses/>. */ #ifndef NMOD_VEC_H #define NMOD_VEC_H #ifdef NMOD_VEC_INLINES_C #define NMOD_VEC_INLINE FLINT_DLL #else #define NMOD_VEC_INLINE static __inline__ #endif #undef ulong #define ulong ulongxx /* interferes with system includes */ #include <stdlib.h> #undef ulong #include <gmp.h> #define ulong mp_limb_t /* Copyright (C) 2010 William Hart Copyright (C) 2021 Fredrik Johansson This file is part of FLINT. FLINT is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See <https://www.gnu.org/licenses/>. */ #ifndef NMOD_H #define NMOD_H #ifdef NMOD_INLINES_C #define NMOD_INLINE FLINT_DLL #else #define NMOD_INLINE static __inline__ #endif #undef ulong #define ulong ulongxx /* interferes with system includes */ #include <stdlib.h> #undef ulong #include <gmp.h> #define ulong mp_limb_t /* Copyright (C) 2006, 2007, 2008, 2009, 2016 William Hart Copyright (C) 2008, Peter Shrimpton Copyright (C) 2009, Tom Boothby Copyright (C) 2010, Fredrik Johansson This file is part of FLINT. FLINT is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See <https://www.gnu.org/licenses/>. */ #ifndef ULONG_EXTRAS_H #define ULONG_EXTRAS_H #ifdef ULONG_EXTRAS_INLINES_C #define ULONG_EXTRAS_INLINE FLINT_DLL #else #define ULONG_EXTRAS_INLINE static __inline__ #endif #include <gmp.h> #ifdef __cplusplus extern "C" { #endif typedef struct pair_s { ulong x, y; } n_pair_t; #define FLINT_MAX_FACTORS_IN_LIMB 15 typedef struct { int num; int exp[FLINT_MAX_FACTORS_IN_LIMB]; ulong p[FLINT_MAX_FACTORS_IN_LIMB]; } n_factor_t; #define FLINT_ODDPRIME_SMALL_CUTOFF 4096 #define FLINT_NUM_PRIMES_SMALL 172 #define FLINT_PRIMES_SMALL_CUTOFF 1030 #define FLINT_PSEUDOSQUARES_CUTOFF 1000 #define FLINT_FACTOR_TRIAL_PRIMES 3000 /* nth_prime(FLINT_FACTOR_TRIAL_PRIMES) */ #define FLINT_FACTOR_TRIAL_PRIMES_PRIME UWORD(27449) #define FLINT_FACTOR_TRIAL_CUTOFF (UWORD(27449) * UWORD(27449)) #define FLINT_PRIMES_TAB_DEFAULT_CUTOFF 1000000 #define FLINT_FACTOR_SQUFOF_ITERS 50000 #define FLINT_FACTOR_ONE_LINE_MAX (UWORD(1)<<39) #define FLINT_FACTOR_ONE_LINE_ITERS 40000 #define FLINT_PRIME_PI_ODD_LOOKUP_CUTOFF 311 #define FLINT_SIEVE_SIZE 65536 #if FLINT64 #define UWORD_MAX_PRIME UWORD(18446744073709551557) #else #define UWORD_MAX_PRIME UWORD(4294967291) #endif #define UWORD_HALF (UWORD_MAX / 2 + 1) typedef struct { slong small_i; slong small_num; unsigned int * small_primes; ulong sieve_a; ulong sieve_b; slong sieve_i; slong sieve_num; char * sieve; } n_primes_struct; typedef n_primes_struct n_primes_t[1]; FLINT_DLL void n_primes_init(n_primes_t iter); FLINT_DLL void n_primes_clear(n_primes_t iter); FLINT_DLL void n_primes_extend_small(n_primes_t iter, ulong bound); FLINT_DLL void n_primes_sieve_range(n_primes_t iter, ulong a, ulong b); FLINT_DLL void n_primes_jump_after(n_primes_t iter, ulong n); ULONG_EXTRAS_INLINE ulong n_primes_next(n_primes_t iter) { if (iter->small_i < iter->small_num) return iter->small_primes[(iter->small_i)++]; for (;;) { while (iter->sieve_i < iter->sieve_num) if (iter->sieve[iter->sieve_i++] != 0) return iter->sieve_a + 2 * (iter->sieve_i - 1); if (iter->sieve_b == 0) n_primes_jump_after(iter, iter->small_primes[iter->small_num-1]); else n_primes_jump_after(iter, iter->sieve_b); } } FLINT_DLL extern const unsigned int flint_primes_small[]; extern FLINT_TLS_PREFIX ulong * _flint_primes[FLINT_BITS]; extern FLINT_TLS_PREFIX double * _flint_prime_inverses[FLINT_BITS]; extern FLINT_TLS_PREFIX int _flint_primes_used; FLINT_DLL void n_compute_primes(ulong num_primes); FLINT_DLL void n_cleanup_primes(void); FLINT_DLL const ulong * n_primes_arr_readonly(ulong n); FLINT_DLL const double * n_prime_inverses_arr_readonly(ulong n); /* Checked arithmetic ********************************************************/ ULONG_EXTRAS_INLINE int n_mul_checked(ulong * a, ulong b, ulong c) { ulong ahi, alo; umul_ppmm(ahi, alo, b, c); *a = alo; return 0 != ahi; } ULONG_EXTRAS_INLINE int n_add_checked(ulong * a, ulong b, ulong c) { int of = b + c < b; *a = b + c; return of; } ULONG_EXTRAS_INLINE int n_sub_checked(ulong * a, ulong b, ulong c) { int of = b < c; *a = b - c; return of; } /*****************************************************************************/ FLINT_DLL ulong n_randlimb(flint_rand_t state); FLINT_DLL ulong n_randint(flint_rand_t state, ulong limit); FLINT_DLL ulong n_urandint(flint_rand_t state, ulong limit); FLINT_DLL ulong n_randbits(flint_rand_t state, unsigned int bits); FLINT_DLL ulong n_randtest_bits(flint_rand_t state, int bits); FLINT_DLL ulong n_randtest(flint_rand_t state); FLINT_DLL ulong n_randtest_not_zero(flint_rand_t state); FLINT_DLL ulong n_randprime(flint_rand_t state, ulong bits, int proved); FLINT_DLL ulong n_randtest_prime(flint_rand_t state, int proved); FLINT_DLL ulong n_pow(ulong n, ulong exp); FLINT_DLL ulong n_flog(ulong n, ulong b); FLINT_DLL ulong n_clog(ulong n, ulong b); FLINT_DLL ulong n_clog_2exp(ulong n, ulong b); ULONG_EXTRAS_INLINE double n_precompute_inverse(ulong n) { return (double) 1 / (double) n; } FLINT_DLL ulong n_preinvert_limb(ulong n); FLINT_DLL ulong n_preinvert_limb_prenorm(ulong n); /* deprecated -- originally defined in longlong.h */ #define invert_limb(dinv, d) \ do { \ (dinv) = n_preinvert_limb_prenorm(d); \ } while (0) FLINT_DLL ulong n_mod_precomp(ulong a, ulong n, double ninv); FLINT_DLL ulong n_mod2_precomp(ulong a, ulong n, double ninv); FLINT_DLL ulong n_divrem2_precomp(ulong * q, ulong a, ulong n, double npre); FLINT_DLL ulong n_divrem2_preinv(ulong * q, ulong a, ulong n, ulong ninv); FLINT_DLL ulong n_div2_preinv(ulong a, ulong n, ulong ninv); FLINT_DLL ulong n_mod2_preinv(ulong a, ulong n, ulong ninv); FLINT_DLL ulong n_ll_mod_preinv(ulong a_hi, ulong a_lo, ulong n, ulong ninv); FLINT_DLL ulong n_lll_mod_preinv(ulong a_hi, ulong a_mi, ulong a_lo, ulong n, ulong ninv); FLINT_DLL ulong n_mulmod_precomp(ulong a, ulong b, ulong n, double ninv); ULONG_EXTRAS_INLINE ulong n_mulmod2_preinv(ulong a, ulong b, ulong n, ulong ninv) { ulong p1, p2; FLINT_ASSERT(n != 0); umul_ppmm(p1, p2, a, b); return n_ll_mod_preinv(p1, p2, n, ninv); } ULONG_EXTRAS_INLINE ulong n_mulmod2(ulong a, ulong b, ulong n) { ulong p1, p2, ninv; FLINT_ASSERT(n != 0); ninv = n_preinvert_limb(n); umul_ppmm(p1, p2, a, b); return n_ll_mod_preinv(p1, p2, n, ninv); } FLINT_DLL ulong n_mulmod_preinv(ulong a, ulong b, ulong n, ulong ninv, ulong norm); FLINT_DLL ulong n_powmod_ui_precomp(ulong a, ulong exp, ulong n, double npre); FLINT_DLL ulong n_powmod_precomp(ulong a, slong exp, ulong n, double npre); ULONG_EXTRAS_INLINE ulong n_powmod(ulong a, slong exp, ulong n) { double npre = n_precompute_inverse(n); return n_powmod_precomp(a, exp, n, npre); } /* This function is in fmpz.h FLINT_DLL ulong n_powmod2_fmpz_preinv(ulong a, const fmpz_t exp, ulong n, ulong ninv); */ FLINT_DLL ulong n_powmod2_preinv(ulong a, slong exp, ulong n, ulong ninv); FLINT_DLL ulong n_powmod2_ui_preinv(ulong a, ulong exp, ulong n, ulong ninv); FLINT_DLL ulong n_powmod_ui_preinv(ulong a, ulong exp, ulong n, ulong ninv, ulong norm); ULONG_EXTRAS_INLINE ulong n_powmod2(ulong a, slong exp, ulong n) { ulong ninv; FLINT_ASSERT(n != 0); ninv = n_preinvert_limb(n); return n_powmod2_preinv(a, exp, n, ninv); } ULONG_EXTRAS_INLINE ulong n_addmod(ulong x, ulong y, ulong n) { FLINT_ASSERT(x < n); FLINT_ASSERT(y < n); FLINT_ASSERT(n != 0); return (n - y > x ? x + y : x + y - n); } ULONG_EXTRAS_INLINE ulong n_submod(ulong x, ulong y, ulong n) { FLINT_ASSERT(x < n); FLINT_ASSERT(y < n); FLINT_ASSERT(n != 0); return (y > x ? x - y + n : x - y); } ULONG_EXTRAS_INLINE ulong n_negmod(ulong x, ulong n) { FLINT_ASSERT(x < n); FLINT_ASSERT(n != 0); return n_submod(0, x, n); } FLINT_DLL ulong n_sqrtmod(ulong a, ulong p); FLINT_DLL slong n_sqrtmod_2pow(ulong ** sqrt, ulong a, slong exp); FLINT_DLL slong n_sqrtmod_primepow(ulong ** sqrt, ulong a, ulong p, slong exp); FLINT_DLL slong n_sqrtmodn(ulong ** sqrt, ulong a, n_factor_t * fac); FLINT_DLL ulong n_gcd(ulong x, ulong y); FLINT_DLL ulong n_xgcd(ulong * a, ulong * b, ulong x, ulong y); FLINT_DLL ulong n_gcdinv(ulong * a, ulong x, ulong y); ULONG_EXTRAS_INLINE ulong n_invmod(ulong x, ulong y) { ulong r, g; g = n_gcdinv(&r, x, y); if (g != 1) flint_throw(FLINT_IMPINV, "Cannot invert modulo %wd*%wd\n", g, y/g); return r; } FLINT_DLL ulong n_CRT(ulong r1, ulong m1, ulong r2, ulong m2); FLINT_DLL ulong n_revbin(ulong in, ulong bits); FLINT_DLL int n_jacobi(slong x, ulong y); FLINT_DLL int n_jacobi_unsigned(ulong x, ulong y); FLINT_DLL int _n_jacobi_unsigned(ulong x, ulong y, unsigned int r); FLINT_DLL ulong n_sqrt(ulong a); FLINT_DLL ulong n_sqrtrem(ulong * r, ulong a); FLINT_DLL int n_is_square(ulong x); FLINT_DLL double n_cbrt_estimate(double a); FLINT_DLL ulong n_cbrt(ulong a); FLINT_DLL ulong n_cbrt_binary_search(ulong x); FLINT_DLL ulong n_cbrt_newton_iteration(ulong n); FLINT_DLL ulong n_cbrt_chebyshev_approx(ulong n); FLINT_DLL ulong n_cbrtrem(ulong* remainder, ulong n); FLINT_DLL int n_is_perfect_power235(ulong n); FLINT_DLL int n_is_perfect_power(ulong * root, ulong n); FLINT_DLL int n_divides(mp_limb_t * q, mp_limb_t n, mp_limb_t p); FLINT_DLL int n_is_oddprime_small(ulong n); FLINT_DLL int n_is_oddprime_binary(ulong n); FLINT_DLL int n_is_probabprime_fermat(ulong n, ulong i); FLINT_DLL int n_is_probabprime_fibonacci(ulong n); FLINT_DLL int n_is_probabprime_lucas(ulong n); FLINT_DLL int n_is_probabprime_BPSW(ulong n); FLINT_DLL int n_is_strong_probabprime_precomp(ulong n, double npre, ulong a, ulong d); FLINT_DLL int n_is_strong_probabprime2_preinv(ulong n, ulong ninv, ulong a, ulong d); FLINT_DLL int n_is_probabprime(ulong n); FLINT_DLL int n_is_prime_pseudosquare(ulong n); FLINT_DLL int n_is_prime_pocklington(ulong n, ulong iterations); FLINT_DLL int n_is_prime(ulong n); FLINT_DLL ulong n_nth_prime(ulong n); FLINT_DLL void n_nth_prime_bounds(ulong *lo, ulong *hi, ulong n); FLINT_DLL ulong n_prime_pi(ulong n); FLINT_DLL void n_prime_pi_bounds(ulong *lo, ulong *hi, ulong n); FLINT_DLL int n_remove(ulong * n, ulong p); FLINT_DLL int n_remove2_precomp(ulong * n, ulong p, double ppre); ULONG_EXTRAS_INLINE void n_factor_init(n_factor_t * factors) { factors->num = UWORD(0); } FLINT_DLL void n_factor_insert(n_factor_t * factors, ulong p, ulong exp); FLINT_DLL ulong n_factor_trial_range(n_factor_t * factors, ulong n, ulong start, ulong num_primes); FLINT_DLL ulong n_factor_trial_partial(n_factor_t * factors, ulong n, ulong * prod, ulong num_primes, ulong limit); FLINT_DLL ulong n_factor_trial(n_factor_t * factors, ulong n, ulong num_primes); FLINT_DLL ulong n_factor_partial(n_factor_t * factors, ulong n, ulong limit, int proved); FLINT_DLL ulong n_factor_power235(ulong *exp, ulong n); FLINT_DLL ulong n_factor_one_line(ulong n, ulong iters); FLINT_DLL ulong n_factor_lehman(ulong n); FLINT_DLL ulong n_factor_SQUFOF(ulong n, ulong iters); FLINT_DLL void n_factor(n_factor_t * factors, ulong n, int proved); FLINT_DLL ulong n_factor_pp1(ulong n, ulong B1, ulong c); FLINT_DLL ulong n_factor_pp1_wrapper(ulong n); FLINT_DLL void n_factor_pp1_table_insert(slong bits, slong B1, slong count); FLINT_DLL int n_factor_pollard_brent_single(ulong *factor, ulong n, ulong ninv, ulong ai, ulong xi, ulong normbits, ulong max_iters); FLINT_DLL int n_factor_pollard_brent(ulong *factor, flint_rand_t state, ulong n_in, ulong max_tries, ulong max_iters); FLINT_DLL int n_is_squarefree(ulong n); FLINT_DLL int n_moebius_mu(ulong n); FLINT_DLL void n_moebius_mu_vec(int * mu, ulong len); FLINT_DLL ulong n_euler_phi(ulong n); FLINT_DLL int n_sizeinbase(ulong n, int base); FLINT_DLL ulong n_nextprime(ulong n, int proved); FLINT_DLL ulong n_factorial_mod2_preinv(ulong n, ulong p, ulong pinv); FLINT_DLL ulong n_factorial_fast_mod2_preinv(ulong n, ulong p, ulong pinv); FLINT_DLL ulong n_primitive_root_prime_prefactor(ulong p, n_factor_t * factors); FLINT_DLL ulong n_primitive_root_prime(ulong p); FLINT_DLL ulong n_discrete_log_bsgs(ulong b, ulong a, ulong n); FLINT_DLL ulong n_root_estimate(double a, int n); FLINT_DLL ulong n_rootrem(ulong* remainder, ulong n, ulong root); FLINT_DLL ulong n_root(ulong n, ulong root); /***** ECM functions *********************************************************/ typedef struct n_ecm_s { ulong x, z; /* the coordinates */ ulong a24; /* value (a + 2)/4 */ ulong ninv; ulong normbits; ulong one; unsigned char *GCD_table; /* checks whether baby step int is coprime to Primorial or not */ unsigned char **prime_table; } n_ecm_s; typedef n_ecm_s n_ecm_t[1]; FLINT_DLL void n_factor_ecm_double(ulong *x, ulong *z, ulong x0, ulong z0, ulong n, n_ecm_t n_ecm_inf); FLINT_DLL void n_factor_ecm_add(ulong *x, ulong *z, ulong x1, ulong z1, ulong x2, ulong z2, ulong x0, ulong z0, ulong n, n_ecm_t n_ecm_inf); FLINT_DLL void n_factor_ecm_mul_montgomery_ladder(ulong *x, ulong *z, ulong x0, ulong z0, ulong k, ulong n, n_ecm_t n_ecm_inf); FLINT_DLL int n_factor_ecm_select_curve(ulong *f, ulong sig, ulong n, n_ecm_t n_ecm_inf); FLINT_DLL int n_factor_ecm_stage_I(ulong *f, const ulong *prime_array, ulong num, ulong B1, ulong n, n_ecm_t n_ecm_inf); FLINT_DLL int n_factor_ecm_stage_II(ulong *f, ulong B1, ulong B2, ulong P, ulong n, n_ecm_t n_ecm_inf); FLINT_DLL int n_factor_ecm(ulong *f, ulong curves, ulong B1, ulong B2, flint_rand_t state, ulong n); FLINT_DLL mp_limb_t n_mulmod_precomp_shoup(mp_limb_t w, mp_limb_t p); ULONG_EXTRAS_INLINE mp_limb_t n_mulmod_shoup(mp_limb_t w, mp_limb_t t, mp_limb_t w_precomp, mp_limb_t p) { mp_limb_t q, r, p_hi, p_lo; umul_ppmm(p_hi, p_lo, w_precomp, t); q = p_hi; r = w * t; r -= q * p; if (r >= p) { r -= p; } return r; } #ifdef __cplusplus } #endif #endif #ifdef __cplusplus extern "C" { #endif typedef struct { mp_limb_t n; mp_limb_t ninv; flint_bitcnt_t norm; } nmod_t; #define NMOD_RED2(r, a_hi, a_lo, mod) \ do { \ mp_limb_t q0xx, q1xx, r1xx; \ const mp_limb_t u1xx = ((a_hi)<<(mod).norm) + r_shift((a_lo), FLINT_BITS - (mod).norm); \ const mp_limb_t u0xx = ((a_lo)<<(mod).norm); \ const mp_limb_t nxx = ((mod).n<<(mod).norm); \ umul_ppmm(q1xx, q0xx, (mod).ninv, u1xx); \ add_ssaaaa(q1xx, q0xx, q1xx, q0xx, u1xx, u0xx); \ r1xx = (u0xx - (q1xx + 1)*nxx); \ if (r1xx > q0xx) r1xx += nxx; \ if (r1xx < nxx) r = (r1xx>>(mod).norm); \ else r = ((r1xx - nxx)>>(mod).norm); \ } while (0) #define NMOD_RED(r, a, mod) \ do { \ NMOD_RED2(r, 0, a, mod); \ } while (0) #define NMOD2_RED2(r, a_hi, a_lo, mod) \ do { \ mp_limb_t v_hi; \ NMOD_RED(v_hi, a_hi, mod); \ NMOD_RED2(r, v_hi, a_lo, mod); \ } while (0) #define NMOD_RED3(r, a_hi, a_me, a_lo, mod) \ do { \ mp_limb_t v_hi; \ NMOD_RED2(v_hi, a_hi, a_me, mod); \ NMOD_RED2(r, v_hi, a_lo, mod); \ } while (0) #define NMOD_BITS(mod) (FLINT_BITS - ((mod).norm)) #define NMOD_CAN_USE_SHOUP(mod) ((mod).norm > 0) #define NMOD_MUL_PRENORM(res, a, b, mod) \ do { \ mp_limb_t q0xx, q1xx, rxx, p_hixx, p_loxx; \ mp_limb_t nxx, ninvxx; \ unsigned int normxx; \ ninvxx = (mod).ninv; \ normxx = (mod).norm; \ nxx = (mod).n << normxx; \ umul_ppmm(p_hixx, p_loxx, (a), (b)); \ umul_ppmm(q1xx, q0xx, ninvxx, p_hixx); \ add_ssaaaa(q1xx, q0xx, q1xx, q0xx, p_hixx, p_loxx); \ rxx = (p_loxx - (q1xx + 1) * nxx); \ if (rxx > q0xx) \ rxx += nxx; \ rxx = (rxx < nxx ? rxx : rxx - nxx) >> normxx; \ (res) = rxx; \ } while (0) #define NMOD_MUL_FULLWORD(res, a, b, mod) \ do { \ mp_limb_t q0xx, q1xx, rxx, p_hixx, p_loxx; \ mp_limb_t nxx, ninvxx; \ ninvxx = (mod).ninv; \ nxx = (mod).n; \ umul_ppmm(p_hixx, p_loxx, (a), (b)); \ umul_ppmm(q1xx, q0xx, ninvxx, p_hixx); \ add_ssaaaa(q1xx, q0xx, q1xx, q0xx, p_hixx, p_loxx); \ rxx = (p_loxx - (q1xx + 1) * nxx); \ if (rxx > q0xx) \ rxx += nxx; \ rxx = (rxx < nxx ? rxx : rxx - nxx); \ (res) = rxx; \ } while (0) NMOD_INLINE mp_limb_t nmod_set_ui(ulong x, nmod_t mod) { if (x < mod.n) return x; NMOD_RED(x, x, mod); return x; } NMOD_INLINE mp_limb_t nmod_set_si(slong x, nmod_t mod) { ulong res = FLINT_ABS(x); NMOD_RED(res, res, mod); return (res == 0 || x > 0) ? res : mod.n - res; } NMOD_INLINE mp_limb_t _nmod_add(mp_limb_t a, mp_limb_t b, nmod_t mod) { const mp_limb_t sum = a + b; return sum - mod.n + ((((mp_limb_signed_t)(sum - mod.n))>>(FLINT_BITS - 1)) & mod.n); } NMOD_INLINE mp_limb_t _nmod_sub(mp_limb_t a, mp_limb_t b, nmod_t mod) { const mp_limb_t diff = a - b; return ((((mp_limb_signed_t)diff)>>(FLINT_BITS - 1)) & mod.n) + diff; } NMOD_INLINE mp_limb_t nmod_add(mp_limb_t a, mp_limb_t b, nmod_t mod) { const mp_limb_t neg = mod.n - a; if (neg > b) return a + b; else return b - neg; } NMOD_INLINE mp_limb_t nmod_sub(mp_limb_t a, mp_limb_t b, nmod_t mod) { const mp_limb_t diff = a - b; if (a < b) return mod.n + diff; else return diff; } NMOD_INLINE mp_limb_t nmod_neg(mp_limb_t a, nmod_t mod) { if (a) return mod.n - a; else return 0; } NMOD_INLINE mp_limb_t nmod_mul(mp_limb_t a, mp_limb_t b, nmod_t mod) { mp_limb_t res; NMOD_MUL_PRENORM(res, a, b << mod.norm, mod); return res; } NMOD_INLINE mp_limb_t _nmod_mul_fullword(mp_limb_t a, mp_limb_t b, nmod_t mod) { mp_limb_t res; NMOD_MUL_FULLWORD(res, a, b, mod); return res; } NMOD_INLINE mp_limb_t nmod_addmul(mp_limb_t a, mp_limb_t b, mp_limb_t c, nmod_t mod) { return nmod_add(a, nmod_mul(b, c, mod), mod); } #define NMOD_ADDMUL(r, a, b, mod) \ do { \ (r) = nmod_addmul((r), (a), (b), (mod)); \ } while (0) NMOD_INLINE mp_limb_t nmod_inv(mp_limb_t a, nmod_t mod) { return n_invmod(a, mod.n); } NMOD_INLINE mp_limb_t nmod_div(mp_limb_t a, mp_limb_t b, nmod_t mod) { return nmod_mul(a, n_invmod(b, mod.n), mod); } NMOD_INLINE mp_limb_t nmod_pow_ui(mp_limb_t a, ulong exp, nmod_t mod) { return n_powmod2_ui_preinv(a, exp, mod.n, mod.ninv); } /* This function is in fmpz.h FMPZ_INLINE mp_limb_t nmod_pow_fmpz(mp_limb_t a, const fmpz_t exp, nmod_t mod) */ NMOD_INLINE void nmod_init(nmod_t * mod, mp_limb_t n) { mod->n = n; mod->ninv = n_preinvert_limb(n); count_leading_zeros(mod->norm, n); } /* discrete logs a la Pohlig - Hellman ***************************************/ typedef struct { mp_limb_t gammapow; ulong cm; } nmod_discrete_log_pohlig_hellman_table_entry_struct; typedef struct { slong exp; ulong prime; mp_limb_t gamma; mp_limb_t gammainv; mp_limb_t startingbeta; ulong co; ulong startinge; ulong idem; ulong cbound; ulong dbound; nmod_discrete_log_pohlig_hellman_table_entry_struct * table; /* length cbound */ } nmod_discrete_log_pohlig_hellman_entry_struct; typedef struct { nmod_t mod; /* p is mod.n */ mp_limb_t alpha; /* p.r. of p */ mp_limb_t alphainv; slong num_factors; /* factors of p - 1*/ nmod_discrete_log_pohlig_hellman_entry_struct * entries; } nmod_discrete_log_pohlig_hellman_struct; typedef nmod_discrete_log_pohlig_hellman_struct nmod_discrete_log_pohlig_hellman_t[1]; FLINT_DLL void nmod_discrete_log_pohlig_hellman_init( nmod_discrete_log_pohlig_hellman_t L); FLINT_DLL void nmod_discrete_log_pohlig_hellman_clear( nmod_discrete_log_pohlig_hellman_t L); FLINT_DLL double nmod_discrete_log_pohlig_hellman_precompute_prime( nmod_discrete_log_pohlig_hellman_t L, mp_limb_t p); FLINT_DLL ulong nmod_discrete_log_pohlig_hellman_run( const nmod_discrete_log_pohlig_hellman_t L, mp_limb_t y); NMOD_INLINE mp_limb_t nmod_discrete_log_pohlig_hellman_primitive_root( const nmod_discrete_log_pohlig_hellman_t L) { return L->alpha; } #ifdef __cplusplus } #endif #endif #ifdef __cplusplus extern "C" { #endif #define NMOD_VEC_NORM(vec, i) \ do { \ while ((i) && vec[(i) - 1] == UWORD(0)) \ (i)--; \ } while (0) NMOD_VEC_INLINE mp_ptr _nmod_vec_init(slong len) { return (mp_ptr) flint_malloc(len * sizeof(mp_limb_t)); } NMOD_VEC_INLINE void _nmod_vec_clear(mp_ptr vec) { flint_free(vec); } FLINT_DLL void _nmod_vec_randtest(mp_ptr vec, flint_rand_t state, slong len, nmod_t mod); NMOD_VEC_INLINE void _nmod_vec_zero(mp_ptr vec, slong len) { flint_mpn_zero(vec, len); } FLINT_DLL flint_bitcnt_t _nmod_vec_max_bits(mp_srcptr vec, slong len); NMOD_VEC_INLINE void _nmod_vec_set(mp_ptr res, mp_srcptr vec, slong len) { flint_mpn_copyi(res, vec, len); } NMOD_VEC_INLINE void _nmod_vec_swap(mp_ptr a, mp_ptr b, slong length) { slong i; for (i = 0; i < length; i++) { mp_limb_t t = a[i]; a[i] = b[i]; b[i] = t; } } NMOD_VEC_INLINE int _nmod_vec_equal(mp_srcptr vec, mp_srcptr vec2, slong len) { slong i; for (i = 0; i < len; i++) if (vec[i] != vec2[i]) return 0; return 1; } NMOD_VEC_INLINE int _nmod_vec_is_zero(mp_srcptr vec, slong len) { slong i; for (i = 0; i < len; i++) if (vec[i] != 0) return 0; return 1; } FLINT_DLL void _nmod_vec_reduce(mp_ptr res, mp_srcptr vec, slong len, nmod_t mod); FLINT_DLL void _nmod_vec_add(mp_ptr res, mp_srcptr vec1, mp_srcptr vec2, slong len, nmod_t mod); FLINT_DLL void _nmod_vec_sub(mp_ptr res, mp_srcptr vec1, mp_srcptr vec2, slong len, nmod_t mod); FLINT_DLL void _nmod_vec_neg(mp_ptr res, mp_srcptr vec, slong len, nmod_t mod); FLINT_DLL void _nmod_vec_scalar_mul_nmod(mp_ptr res, mp_srcptr vec, slong len, mp_limb_t c, nmod_t mod); FLINT_DLL void _nmod_vec_scalar_mul_nmod_shoup(mp_ptr res, mp_srcptr vec, slong len, mp_limb_t c, nmod_t mod); FLINT_DLL void _nmod_vec_scalar_addmul_nmod(mp_ptr res, mp_srcptr vec, slong len, mp_limb_t c, nmod_t mod); FLINT_DLL int _nmod_vec_dot_bound_limbs(slong len, nmod_t mod); #define NMOD_VEC_DOT(res, i, len, expr1, expr2, mod, nlimbs) \ do \ { \ mp_limb_t s0, s1, s2, t0, t1; \ s0 = s1 = s2 = UWORD(0); \ switch (nlimbs) \ { \ case 1: \ for (i = 0; i < (len); i++) \ { \ s0 += (expr1) * (expr2); \ } \ NMOD_RED(s0, s0, mod); \ break; \ case 2: \ if (mod.n <= (UWORD(1) << (FLINT_BITS / 2))) \ { \ for (i = 0; i < (len); i++) \ { \ t0 = (expr1) * (expr2); \ add_ssaaaa(s1, s0, s1, s0, 0, t0); \ } \ } \ else if ((len) < 8) \ { \ for (i = 0; i < len; i++) \ { \ umul_ppmm(t1, t0, (expr1), (expr2)); \ add_ssaaaa(s1, s0, s1, s0, t1, t0); \ } \ } \ else \ { \ mp_limb_t v0, v1, u0, u1; \ i = 0; \ if ((len) & 1) \ umul_ppmm(v1, v0, (expr1), (expr2)); \ else \ v0 = v1 = 0; \ for (i = (len) & 1; i < (len); i++) \ { \ umul_ppmm(t1, t0, (expr1), (expr2)); \ add_ssaaaa(s1, s0, s1, s0, t1, t0); \ i++; \ umul_ppmm(u1, u0, (expr1), (expr2)); \ add_ssaaaa(v1, v0, v1, v0, u1, u0); \ } \ add_ssaaaa(s1, s0, s1, s0, v1, v0); \ } \ NMOD2_RED2(s0, s1, s0, mod); \ break; \ default: \ for (i = 0; i < (len); i++) \ { \ umul_ppmm(t1, t0, (expr1), (expr2)); \ add_sssaaaaaa(s2, s1, s0, s2, s1, s0, 0, t1, t0); \ } \ NMOD_RED(s2, s2, mod); \ NMOD_RED3(s0, s2, s1, s0, mod); \ break; \ } \ res = s0; \ } while (0); FLINT_DLL mp_limb_t _nmod_vec_dot(mp_srcptr vec1, mp_srcptr vec2, slong len, nmod_t mod, int nlimbs); FLINT_DLL mp_limb_t _nmod_vec_dot_rev(mp_srcptr vec1, mp_srcptr vec2, slong len, nmod_t mod, int nlimbs); FLINT_DLL mp_limb_t _nmod_vec_dot_ptr(mp_srcptr vec1, const mp_ptr * vec2, slong offset, slong len, nmod_t mod, int nlimbs); #ifdef __cplusplus } #endif #endif #ifndef FMPZ_CONVERSIONS_H #define FMPZ_CONVERSIONS_H /* turn a pointer to an __mpz_struct into a fmpz_t */ #define PTR_TO_COEFF(x) (((ulong) (x) >> 2) | (WORD(1) << (FLINT_BITS - 2))) /* turns an fmpz into a pointer to an mpz */ #define COEFF_TO_PTR(x) ((__mpz_struct *) (((ulong)x) << 2)) #endif /* FMPZ_CONVERSIONS_H */ #if FLINT_USES_PTHREAD #include <pthread.h> #endif #ifdef __cplusplus extern "C" { #endif typedef slong fmpz; typedef fmpz fmpz_t[1]; typedef gmp_randstate_t fmpz_randstate_t; extern __mpz_struct * fmpz_arr; extern gmp_randstate_t fmpz_randstate; typedef struct { mp_ptr dinv; slong n; flint_bitcnt_t norm; } fmpz_preinvn_struct; typedef fmpz_preinvn_struct fmpz_preinvn_t[1]; typedef struct { int count; #if FLINT_USES_PTHREAD pthread_t thread; #endif void * address; } fmpz_block_header_s; /* The largest bit count for an fmpz to be small */ #define SMALL_FMPZ_BITCOUNT_MAX (FLINT_BITS - 2) /* maximum positive value a small coefficient can have */ #define COEFF_MAX ((WORD(1) << SMALL_FMPZ_BITCOUNT_MAX) - WORD(1)) /* minimum negative value a small coefficient can have */ #define COEFF_MIN (-((WORD(1) << SMALL_FMPZ_BITCOUNT_MAX) - WORD(1))) #define COEFF_IS_MPZ(x) (((x) >> SMALL_FMPZ_BITCOUNT_MAX) == WORD(1)) /* is x a pointer not an integer */ FLINT_DLL __mpz_struct * _fmpz_new_mpz(void); FLINT_DLL void _fmpz_clear_mpz(fmpz f); FLINT_DLL void _fmpz_cleanup_mpz_content(void); FLINT_DLL void _fmpz_cleanup(void); FLINT_DLL __mpz_struct * _fmpz_promote(fmpz_t f); FLINT_DLL __mpz_struct * _fmpz_promote_val(fmpz_t f); FMPZ_INLINE void _fmpz_demote(fmpz_t f) { /* warning, if fmpz_demote changes, fmpz_zero must also be changed to match */ if (COEFF_IS_MPZ(*f)) { _fmpz_clear_mpz(*f); (*f) = WORD(0); } } FLINT_DLL void _fmpz_demote_val(fmpz_t f); FLINT_DLL void _fmpz_init_readonly_mpz(fmpz_t f, const mpz_t z); FLINT_DLL void _fmpz_clear_readonly_mpz(mpz_t); FMPZ_INLINE void fmpz_init(fmpz_t f) { (*f) = WORD(0); } FLINT_DLL void fmpz_init2(fmpz_t f, ulong limbs); FMPZ_INLINE void fmpz_init_set(fmpz_t f, const fmpz_t g) { if (!COEFF_IS_MPZ(*g)) { *f = *g; } else { __mpz_struct *ptr; ptr = _fmpz_new_mpz(); *f = PTR_TO_COEFF(ptr); mpz_set(ptr, COEFF_TO_PTR(*g)); } } FMPZ_INLINE void fmpz_init_set_ui(fmpz_t f, ulong g) { if (g <= COEFF_MAX) { *f = g; } else { __mpz_struct *ptr; ptr = _fmpz_new_mpz(); *f = PTR_TO_COEFF(ptr); flint_mpz_set_ui(ptr, g); } } FMPZ_INLINE void fmpz_init_set_si(fmpz_t f, slong g) { if (COEFF_MIN <= g && g <= COEFF_MAX) { *f = g; } else { __mpz_struct *ptr; ptr = _fmpz_new_mpz(); *f = PTR_TO_COEFF(ptr); flint_mpz_set_si(ptr, g); } } FMPZ_INLINE void fmpz_clear(fmpz_t f) { if (COEFF_IS_MPZ(*f)) _fmpz_clear_mpz(*f); } FLINT_DLL void fmpz_randbits(fmpz_t f, flint_rand_t state, flint_bitcnt_t bits); FLINT_DLL void fmpz_randm(fmpz_t f, flint_rand_t state, const fmpz_t m); FLINT_DLL void fmpz_randtest(fmpz_t f, flint_rand_t state, flint_bitcnt_t bits); FLINT_DLL void fmpz_randtest_unsigned(fmpz_t f, flint_rand_t state, flint_bitcnt_t bits); FLINT_DLL void fmpz_randtest_not_zero(fmpz_t f, flint_rand_t state, flint_bitcnt_t bits); FLINT_DLL void fmpz_randtest_mod(fmpz_t f, flint_rand_t state, const fmpz_t m); FLINT_DLL void fmpz_randtest_mod_signed(fmpz_t f, flint_rand_t state, const fmpz_t m); FLINT_DLL void fmpz_randprime(fmpz_t f, flint_rand_t state, flint_bitcnt_t bits, int proved); FLINT_DLL slong fmpz_get_si(const fmpz_t f); FLINT_DLL ulong fmpz_get_ui(const fmpz_t f); FLINT_DLL mp_limb_t fmpz_get_nmod(const fmpz_t f, nmod_t mod); FMPZ_INLINE void fmpz_get_uiui(mp_limb_t * hi, mp_limb_t * low, const fmpz_t f) { if (!COEFF_IS_MPZ(*f)) { *low = *f; *hi = 0; } else { __mpz_struct * mpz = COEFF_TO_PTR(*f); *low = mpz->_mp_d[0]; *hi = mpz->_mp_size == 2 ? mpz->_mp_d[1] : 0; } } FMPZ_INLINE void fmpz_set_si(fmpz_t f, slong val) { if (val < COEFF_MIN || val > COEFF_MAX) /* val is large */ { __mpz_struct *mpz_coeff = _fmpz_promote(f); flint_mpz_set_si(mpz_coeff, val); } else { _fmpz_demote(f); *f = val; /* val is small */ } } FMPZ_INLINE void fmpz_set_ui(fmpz_t f, ulong val) { if (val > COEFF_MAX) /* val is large */ { __mpz_struct *mpz_coeff = _fmpz_promote(f); flint_mpz_set_ui(mpz_coeff, val); } else { _fmpz_demote(f); *f = val; /* val is small */ } } FMPZ_INLINE void fmpz_neg_ui(fmpz_t f, ulong val) { if (val > COEFF_MAX) { __mpz_struct *mpz_coeff = _fmpz_promote(f); flint_mpz_set_ui(mpz_coeff, val); mpz_neg(mpz_coeff, mpz_coeff); } else { _fmpz_demote(f); *f = -(slong) val; } } FMPZ_INLINE void fmpz_set_uiui(fmpz_t f, mp_limb_t hi, mp_limb_t lo) { if (hi == 0) { fmpz_set_ui(f, lo); } else { __mpz_struct *z = _fmpz_promote(f); if (z->_mp_alloc < 2) mpz_realloc2(z, 2 * FLINT_BITS); z->_mp_d[0] = lo; z->_mp_d[1] = hi; z->_mp_size = 2; } } FMPZ_INLINE void fmpz_neg_uiui(fmpz_t f, mp_limb_t hi, mp_limb_t lo) { if (hi == 0) { fmpz_neg_ui(f, lo); } else { __mpz_struct *z = _fmpz_promote(f); if (z->_mp_alloc < 2) mpz_realloc2(z, 2 * FLINT_BITS); z->_mp_d[0] = lo; z->_mp_d[1] = hi; z->_mp_size = -2; } } FLINT_DLL void fmpz_get_signed_uiui(ulong * hi, ulong * lo, const fmpz_t x); FMPZ_INLINE void fmpz_set_signed_uiui(fmpz_t r, ulong hi, ulong lo) { if (((slong) hi) < 0) { hi = -hi - (lo != 0); lo = -lo; fmpz_neg_uiui(r, hi, lo); } else { fmpz_set_uiui(r, hi, lo); } } FLINT_DLL void fmpz_set_signed_uiuiui(fmpz_t r, ulong hi, ulong mid, ulong lo); FLINT_DLL void fmpz_get_ui_array(ulong * out, slong n, const fmpz_t in); FLINT_DLL void fmpz_set_ui_array(fmpz_t out, const ulong * in, slong n); FLINT_DLL void fmpz_get_signed_ui_array(ulong * out, slong n, const fmpz_t in); FLINT_DLL void fmpz_set_signed_ui_array(fmpz_t out, const ulong * in, slong n); FLINT_DLL void fmpz_get_mpz(mpz_t x, const fmpz_t f); FLINT_DLL void fmpz_set_mpz(fmpz_t f, const mpz_t x); FLINT_DLL double fmpz_get_d(const fmpz_t f); FLINT_DLL void fmpz_set_d(fmpz_t f, double c); FLINT_DLL void fmpz_get_mpf(mpf_t x, const fmpz_t f); FLINT_DLL void fmpz_set_mpf(fmpz_t f, const mpf_t x); #ifdef __MPFR_H FLINT_DLL void fmpz_get_mpfr(mpfr_t x, const fmpz_t f, mpfr_rnd_t rnd); #endif FLINT_DLL int fmpz_get_mpn(mp_ptr *n, fmpz_t n_in); FLINT_DLL int fmpz_set_str(fmpz_t f, const char * str, int b); FLINT_DLL void flint_mpz_init_set_readonly(mpz_t z, const fmpz_t f); FLINT_DLL void flint_mpz_clear_readonly(mpz_t z); FLINT_DLL void fmpz_init_set_readonly(fmpz_t f, const mpz_t z); FLINT_DLL void fmpz_clear_readonly(fmpz_t f); FLINT_DLL int fmpz_abs_fits_ui(const fmpz_t f); FLINT_DLL int fmpz_fits_si(const fmpz_t f); FMPZ_INLINE void fmpz_zero(fmpz_t f) { if (COEFF_IS_MPZ(*f)) _fmpz_clear_mpz(*f); *f = WORD(0); } FMPZ_INLINE void fmpz_one(fmpz_t f) { if (COEFF_IS_MPZ(*f)) { _fmpz_clear_mpz(*f); } *f = WORD(1); } FMPZ_INLINE int fmpz_is_zero(const fmpz_t f) { return (*f == 0); } FMPZ_INLINE int fmpz_is_one(const fmpz_t f) { return (*f == 1); } FMPZ_INLINE int fmpz_is_pm1(const fmpz_t f) { return (*f == 1 || *f == -1); } FLINT_DLL void fmpz_set(fmpz_t f, const fmpz_t g); FLINT_DLL int fmpz_equal(const fmpz_t f, const fmpz_t g); FLINT_DLL int fmpz_equal_si(const fmpz_t f, slong g); FLINT_DLL int fmpz_equal_ui(const fmpz_t f, ulong g); FLINT_DLL int fmpz_read(fmpz_t f); FLINT_DLL int fmpz_fread(FILE * file, fmpz_t f); FLINT_DLL size_t fmpz_inp_raw( fmpz_t x, FILE *fin ); FLINT_DLL int fmpz_print(const fmpz_t x); FLINT_DLL int fmpz_fprint(FILE * file, const fmpz_t x); FLINT_DLL size_t fmpz_out_raw( FILE *fout, const fmpz_t x ); FLINT_DLL size_t fmpz_sizeinbase(const fmpz_t f, int b); FLINT_DLL char * fmpz_get_str(char * str, int b, const fmpz_t f); FMPZ_INLINE void fmpz_swap(fmpz_t f, fmpz_t g) { if (f != g) /* swapping required */ { fmpz t = *f; *f = *g; *g = t; } } FLINT_DLL int fmpz_cmp(const fmpz_t f, const fmpz_t g); FLINT_DLL int fmpz_cmp_ui(const fmpz_t f, ulong g); FLINT_DLL int fmpz_cmp_si(const fmpz_t f, slong g); FLINT_DLL int fmpz_cmpabs(const fmpz_t f, const fmpz_t g); FLINT_DLL int fmpz_cmp2abs(const fmpz_t f, const fmpz_t g); FMPZ_INLINE int fmpz_is_even(const fmpz_t f) { if (!COEFF_IS_MPZ(*f)) { return !((*f) & WORD(1)); } else { return mpz_even_p(COEFF_TO_PTR(*f)); } } FMPZ_INLINE int fmpz_is_odd(const fmpz_t f) { if (!COEFF_IS_MPZ(*f)) { return ((*f) & WORD(1)); } else { return mpz_odd_p(COEFF_TO_PTR(*f)); } } FLINT_DLL mp_size_t fmpz_size(const fmpz_t f); FLINT_DLL int fmpz_sgn(const fmpz_t f); FLINT_DLL flint_bitcnt_t fmpz_bits(const fmpz_t f); FLINT_DLL flint_bitcnt_t fmpz_val2(const fmpz_t x); FMPZ_INLINE void fmpz_neg(fmpz_t f1, const fmpz_t f2) { if (!COEFF_IS_MPZ(*f2)) /* coeff is small */ { fmpz t = -*f2; /* Need to save value in case of aliasing */ _fmpz_demote(f1); *f1 = t; } else /* coeff is large */ { /* No need to retain value in promotion, as if aliased, both already large */ __mpz_struct *mpz_res = _fmpz_promote(f1); mpz_neg(mpz_res, COEFF_TO_PTR(*f2)); } } FLINT_DLL void fmpz_abs(fmpz_t f1, const fmpz_t f2); FLINT_DLL void fmpz_add(fmpz_t f, const fmpz_t g, const fmpz_t h); FLINT_DLL void fmpz_sub(fmpz_t f, const fmpz_t g, const fmpz_t h); FLINT_DLL void fmpz_mul_ui(fmpz_t f, const fmpz_t g, ulong x); FLINT_DLL void fmpz_mul_si(fmpz_t f, const fmpz_t g, slong x); FLINT_DLL void fmpz_mul(fmpz_t f, const fmpz_t g, const fmpz_t h); FLINT_DLL void fmpz_mul_2exp(fmpz_t f, const fmpz_t g, ulong exp); FLINT_DLL void fmpz_one_2exp(fmpz_t f, ulong exp); FLINT_DLL void fmpz_add_ui(fmpz_t f, const fmpz_t g, ulong x); FLINT_DLL void fmpz_sub_ui(fmpz_t f, const fmpz_t g, ulong x); FMPZ_INLINE void fmpz_add_si(fmpz_t f, const fmpz_t g, slong x) { if (x >= 0) fmpz_add_ui(f, g, (ulong) x); else fmpz_sub_ui(f, g, (ulong) -x); } FMPZ_INLINE void fmpz_sub_si(fmpz_t f, const fmpz_t g, slong x) { if (x >= 0) fmpz_sub_ui(f, g, (ulong) x); else fmpz_add_ui(f, g, (ulong) -x); } FMPZ_INLINE void flint_mpz_add_uiui(mpz_ptr a, mpz_srcptr b, ulong c1, ulong c0) { ulong d[2]; mpz_t c; d[0] = c0; d[1] = c1; c->_mp_d = d; c->_mp_alloc = 2; c->_mp_size = d[1] != 0 ? 2 : d[0] != 0; mpz_add(a, b, c); } FMPZ_INLINE void flint_mpz_add_signed_uiui(mpz_ptr a, mpz_srcptr b, ulong c1, ulong c0) { ulong d[2]; ulong c2 = FLINT_SIGN_EXT(c1); mpz_t c; sub_ddmmss(d[1], d[0], c2^c1, c2^c0, c2, c2); c->_mp_d = d; c->_mp_alloc = 2; c->_mp_size = d[1] != 0 ? 2 : d[0] != 0; if (c2 != 0) c->_mp_size = -c->_mp_size; mpz_add(a, b, c); } FMPZ_INLINE void flint_mpz_add_uiuiui(mpz_ptr a, mpz_srcptr b, ulong c2, ulong c1, ulong c0) { ulong d[3]; mpz_t c; d[0] = c0; d[1] = c1; d[2] = c2; c->_mp_d = d; c->_mp_alloc = 3; c->_mp_size = d[2] != 0 ? 3 : d[1] != 0 ? 2 : d[0] != 0; mpz_add(a, b, c); } FLINT_DLL void fmpz_addmul_si(fmpz_t f, const fmpz_t g, slong x); FLINT_DLL void fmpz_submul_si(fmpz_t f, const fmpz_t g, slong x); FLINT_DLL void fmpz_addmul_ui(fmpz_t f, const fmpz_t g, ulong x); FLINT_DLL void fmpz_submul_ui(fmpz_t f, const fmpz_t g, ulong x); FLINT_DLL void fmpz_addmul(fmpz_t f, const fmpz_t g, const fmpz_t h); FLINT_DLL void fmpz_submul(fmpz_t f, const fmpz_t g, const fmpz_t h); FLINT_DLL void fmpz_fmma(fmpz_t f, const fmpz_t a, const fmpz_t b, const fmpz_t c, const fmpz_t d); FLINT_DLL void fmpz_fmms(fmpz_t f, const fmpz_t a, const fmpz_t b, const fmpz_t c, const fmpz_t d); FLINT_DLL void fmpz_pow_ui(fmpz_t f, const fmpz_t g, ulong exp); FLINT_DLL int fmpz_pow_fmpz(fmpz_t a, const fmpz_t b, const fmpz_t e); FLINT_DLL void fmpz_powm_ui(fmpz_t f, const fmpz_t g, ulong exp, const fmpz_t m); FLINT_DLL void fmpz_powm(fmpz_t f, const fmpz_t g, const fmpz_t e, const fmpz_t m); FLINT_DLL void fmpz_setbit(fmpz_t f, ulong i); FLINT_DLL int fmpz_tstbit(const fmpz_t f, ulong i); FLINT_DLL void fmpz_clrbit(fmpz_t f, ulong i); FLINT_DLL void fmpz_complement(fmpz_t r, const fmpz_t f); FLINT_DLL void fmpz_combit(fmpz_t f, ulong i); FLINT_DLL void fmpz_and(fmpz_t r, const fmpz_t a, const fmpz_t b); FLINT_DLL void fmpz_or(fmpz_t r, const fmpz_t a, const fmpz_t b); FLINT_DLL void fmpz_xor(fmpz_t r, const fmpz_t a, const fmpz_t b); FLINT_DLL flint_bitcnt_t fmpz_popcnt(const fmpz_t c); FLINT_DLL double fmpz_dlog(const fmpz_t x); FLINT_DLL slong fmpz_flog(const fmpz_t x, const fmpz_t b); FLINT_DLL slong fmpz_flog_ui(const fmpz_t x, ulong b); FLINT_DLL slong fmpz_clog(const fmpz_t x, const fmpz_t b); FLINT_DLL slong fmpz_clog_ui(const fmpz_t x, ulong b); FLINT_DLL int fmpz_sqrtmod(fmpz_t b, const fmpz_t a, const fmpz_t p); FLINT_DLL void fmpz_sqrt(fmpz_t f, const fmpz_t g); FLINT_DLL int fmpz_is_square(const fmpz_t f); FLINT_DLL int fmpz_root(fmpz_t r, const fmpz_t f, slong n); FLINT_DLL int fmpz_is_perfect_power(fmpz_t root, const fmpz_t f); FLINT_DLL void fmpz_sqrtrem(fmpz_t f, fmpz_t r, const fmpz_t g); FLINT_DLL ulong fmpz_fdiv_ui(const fmpz_t g, ulong h); FMPZ_INLINE ulong fmpz_mod_ui(fmpz_t f, const fmpz_t g, ulong h) { h = fmpz_fdiv_ui(g, h); fmpz_set_ui(f, h); return h; } FLINT_DLL void fmpz_mod(fmpz_t f, const fmpz_t g, const fmpz_t h); FLINT_DLL void fmpz_smod(fmpz_t f, const fmpz_t g, const fmpz_t h); FLINT_DLL void _fmpz_smod(fmpz_t r, const fmpz_t a, const fmpz_t m, int sign, fmpz_t t); FMPZ_INLINE void fmpz_negmod(fmpz_t r, const fmpz_t a, const fmpz_t mod) { if (fmpz_is_zero(a)) fmpz_zero(r); else fmpz_sub(r, mod, a); } FLINT_DLL void fmpz_gcd(fmpz_t f, const fmpz_t g, const fmpz_t h); FLINT_DLL void fmpz_gcd_ui(fmpz_t res, const fmpz_t a, ulong b); FLINT_DLL void fmpz_gcd3(fmpz_t f, const fmpz_t a, const fmpz_t b, const fmpz_t c); FLINT_DLL void fmpz_lcm(fmpz_t f, const fmpz_t g, const fmpz_t h); FLINT_DLL void fmpz_gcdinv(fmpz_t d, fmpz_t a, const fmpz_t f, const fmpz_t g); FLINT_DLL void fmpz_xgcd(fmpz_t d, fmpz_t a, fmpz_t b, const fmpz_t f, const fmpz_t g); FLINT_DLL void fmpz_xgcd_canonical_bezout(fmpz_t d, fmpz_t a, fmpz_t b, const fmpz_t f, const fmpz_t g); FLINT_DLL void fmpz_xgcd_partial(fmpz_t co2, fmpz_t co1, fmpz_t r2, fmpz_t r1, const fmpz_t L); FLINT_DLL int fmpz_invmod(fmpz_t f, const fmpz_t g, const fmpz_t h); FLINT_DLL int fmpz_jacobi(const fmpz_t a, const fmpz_t p); FLINT_DLL int fmpz_kronecker(const fmpz_t a, const fmpz_t n); FLINT_DLL void fmpz_divides_mod_list(fmpz_t xstart, fmpz_t xstride, fmpz_t xlength, const fmpz_t a, const fmpz_t b, const fmpz_t n); FLINT_DLL slong _fmpz_remove(fmpz_t x, const fmpz_t f, double finv); FLINT_DLL slong fmpz_remove(fmpz_t rop, const fmpz_t op, const fmpz_t f); FLINT_DLL void fmpz_divexact(fmpz_t f, const fmpz_t g, const fmpz_t h); FLINT_DLL void fmpz_divexact_si(fmpz_t f, const fmpz_t g, slong h); FLINT_DLL void fmpz_divexact_ui(fmpz_t f, const fmpz_t g, ulong h); FLINT_DLL int fmpz_divisible(const fmpz_t f, const fmpz_t g); FLINT_DLL int fmpz_divides(fmpz_t q, const fmpz_t g, const fmpz_t h); FLINT_DLL int fmpz_divisible_si(const fmpz_t f, slong g); FLINT_DLL void fmpz_cdiv_qr(fmpz_t f, fmpz_t s, const fmpz_t g, const fmpz_t h); FLINT_DLL void fmpz_cdiv_q(fmpz_t f, const fmpz_t g, const fmpz_t h); FLINT_DLL void fmpz_cdiv_q_si(fmpz_t f, const fmpz_t g, slong h); FLINT_DLL void fmpz_cdiv_q_ui(fmpz_t f, const fmpz_t g, ulong h); FLINT_DLL void fmpz_cdiv_q_2exp(fmpz_t f, const fmpz_t g, ulong exp); FLINT_DLL void fmpz_cdiv_r_2exp(fmpz_t f, const fmpz_t g, ulong exp); FLINT_DLL ulong fmpz_cdiv_ui(const fmpz_t g, ulong h); FLINT_DLL void fmpz_fdiv_qr(fmpz_t f, fmpz_t s, const fmpz_t g, const fmpz_t h); FLINT_DLL void fmpz_fdiv_qr_preinvn(fmpz_t f, fmpz_t s, const fmpz_t g, const fmpz_t h, const fmpz_preinvn_t inv); FLINT_DLL void fmpz_fdiv_q(fmpz_t f, const fmpz_t g, const fmpz_t h); FLINT_DLL void fmpz_fdiv_r(fmpz_t f, const fmpz_t g, const fmpz_t h); FLINT_DLL void fmpz_fdiv_q_ui(fmpz_t f, const fmpz_t g, ulong h); FLINT_DLL void fmpz_fdiv_q_si(fmpz_t f, const fmpz_t g, slong h); FLINT_DLL void fmpz_fdiv_q_2exp(fmpz_t f, const fmpz_t g, ulong exp); FLINT_DLL void fmpz_fdiv_r_2exp(fmpz_t f, const fmpz_t g, ulong exp); FLINT_DLL void fmpz_tdiv_q(fmpz_t f, const fmpz_t g, const fmpz_t h); FLINT_DLL void fmpz_tdiv_qr(fmpz_t f, fmpz_t s, const fmpz_t g, const fmpz_t h); FLINT_DLL void fmpz_tdiv_q_ui(fmpz_t f, const fmpz_t g, ulong h); FLINT_DLL void fmpz_tdiv_q_si(fmpz_t f, const fmpz_t g, slong h); FLINT_DLL void fmpz_tdiv_r_2exp(fmpz_t f, const fmpz_t g, ulong exp); FLINT_DLL ulong fmpz_tdiv_ui(const fmpz_t g, ulong h); FLINT_DLL void fmpz_tdiv_q_2exp(fmpz_t f, const fmpz_t g, ulong exp); FLINT_DLL void fmpz_ndiv_qr(fmpz_t q, fmpz_t r, const fmpz_t a, const fmpz_t b); FLINT_DLL void fmpz_preinvn_init(fmpz_preinvn_t inv, const fmpz_t f); FLINT_DLL void fmpz_preinvn_clear(fmpz_preinvn_t inv); FLINT_DLL double fmpz_get_d_2exp(slong * exp, const fmpz_t f); FLINT_DLL void fmpz_set_d_2exp(fmpz_t f, double m, slong exp); FMPZ_INLINE void fmpz_mul2_uiui(fmpz_t f, const fmpz_t g, ulong h1, ulong h2) { mp_limb_t hi, lo; umul_ppmm(hi, lo, h1, h2); if (!hi) { fmpz_mul_ui(f, g, lo); } else { fmpz_mul_ui(f, g, h1); fmpz_mul_ui(f, f, h2); } } FMPZ_INLINE void fmpz_divexact2_uiui(fmpz_t f, const fmpz_t g, ulong h1, ulong h2) { mp_limb_t hi, lo; umul_ppmm(hi, lo, h1, h2); if (!hi) { fmpz_divexact_ui(f, g, lo); } else { fmpz_divexact_ui(f, g, h1); fmpz_divexact_ui(f, f, h2); } } FLINT_DLL void fmpz_mul_tdiv_q_2exp(fmpz_t f, const fmpz_t g, const fmpz_t h, ulong exp); FLINT_DLL void fmpz_mul_si_tdiv_q_2exp(fmpz_t f, const fmpz_t g, slong x, ulong exp); FLINT_DLL void fmpz_fac_ui(fmpz_t f, ulong n); FLINT_DLL void fmpz_fib_ui(fmpz_t f, ulong n); FLINT_DLL void fmpz_bin_uiui(fmpz_t res, ulong n, ulong k); FLINT_DLL void _fmpz_rfac_ui(fmpz_t r, const fmpz_t x, ulong a, ulong b); FLINT_DLL void fmpz_rfac_ui(fmpz_t r, const fmpz_t x, ulong n); FLINT_DLL void fmpz_rfac_uiui(fmpz_t r, ulong x, ulong n); FLINT_DLL int fmpz_bit_pack(mp_ptr arr, flint_bitcnt_t shift, flint_bitcnt_t bits, const fmpz_t coeff, int negate, int borrow); FLINT_DLL int fmpz_bit_unpack(fmpz_t coeff, mp_srcptr arr, flint_bitcnt_t shift, flint_bitcnt_t bits, int negate, int borrow); FLINT_DLL void fmpz_bit_unpack_unsigned(fmpz_t coeff, mp_srcptr arr, flint_bitcnt_t shift, flint_bitcnt_t bits); /* crt ***********************************************************************/ FLINT_DLL void _fmpz_CRT_ui_precomp(fmpz_t out, const fmpz_t r1, const fmpz_t m1, ulong r2, ulong m2, mp_limb_t m2inv, const fmpz_t m1m2, mp_limb_t c, int sign); FLINT_DLL void fmpz_CRT_ui(fmpz_t out, const fmpz_t r1, const fmpz_t m1, ulong r2, ulong m2, int sign); FLINT_DLL void fmpz_CRT(fmpz_t out, const fmpz_t r1, const fmpz_t m1, fmpz_t r2, fmpz_t m2, int sign); FMPZ_INLINE void fmpz_set_ui_smod(fmpz_t f, mp_limb_t x, mp_limb_t m) { if (x <= m / 2) fmpz_set_ui(f, x); else fmpz_set_si(f, x - m); } /* multi CRT *****************************************************************/ typedef struct { slong a_idx; /* index of A */ slong b_idx; /* index of B */ slong c_idx; /* index of C */ fmpz_t b_modulus; fmpz_t c_modulus; } _fmpz_multi_CRT_instr; typedef struct { _fmpz_multi_CRT_instr * prog; /* straight line program */ fmpz * moduli, * fracmoduli; fmpz_t final_modulus; slong moduli_count; flint_bitcnt_t min_modulus_bits; slong length; /* length of prog */ slong alloc; /* alloc of prog */ slong localsize; /* length of outputs required in fmpz_multi_CRT_run */ slong temp1loc, temp2loc, temp3loc, temp4loc; int good; /* the moduli are good for CRT, essentially relatively prime */ } fmpz_multi_CRT_struct; typedef fmpz_multi_CRT_struct fmpz_multi_CRT_t[1]; FLINT_DLL void fmpz_multi_CRT_init(fmpz_multi_CRT_t CRT); FLINT_DLL int fmpz_multi_CRT_precompute(fmpz_multi_CRT_t CRT, const fmpz * moduli, slong len); FLINT_DLL void fmpz_multi_CRT_precomp(fmpz_t output, const fmpz_multi_CRT_t P, const fmpz * inputs, int sign); FLINT_DLL int fmpz_multi_CRT(fmpz_t output, const fmpz * moduli, const fmpz * values, slong len, int sign); FLINT_DLL void fmpz_multi_CRT_clear(fmpz_multi_CRT_t P); FLINT_DLL void _fmpz_multi_CRT_precomp(fmpz * outputs, const fmpz_multi_CRT_t P, const fmpz * inputs, int sign); /* deprecated versions that assume sign = 1 **********************************/ /* deprecated functions and types new functions and types fmpz_multi_crt_t => fmpz_multi_CRT_t fmpz_multi_crt_init => fmpz_multi_CRT_init fmpz_multi_crt_precompute => fmpz_multi_CRT_precompute fmpz_multi_crt_precompute_p gone fmpz_multi_crt_precomp => fmpz_multi_CRT_precomp now with sign option fmpz_multi_crt_precomp_p gone fmpz_multi_crt => fmpz_multi_CRT now with sign option fmpz_multi_crt_clear => fmpz_multi_CRT_clear */ #define fmpz_multi_crt_struct fmpz_multi_CRT_struct #define fmpz_multi_crt_t fmpz_multi_CRT_t #define fmpz_multi_crt_init fmpz_deprecated_multi_crt_init #define fmpz_multi_crt_precompute fmpz_deprecated_multi_crt_precompute #define fmpz_multi_crt_precompute_p fmpz_deprecated_multi_crt_precompute_p #define fmpz_multi_crt_precomp fmpz_deprecated_multi_crt_precomp #define fmpz_multi_crt_precomp_p fmpz_deprecated_multi_crt_precomp_p #define fmpz_multi_crt fmpz_deprecated_multi_crt #define fmpz_multi_crt_clear fmpz_deprecated_multi_crt_clear #define _fmpz_multi_crt_local_size _fmpz_deprecated_multi_crt_local_size #define _fmpz_multi_crt_run _fmpz_deprecated_multi_crt_run #define _fmpz_multi_crt_run_p _fmpz_deprecated_multi_crt_run_p FLINT_DLL void fmpz_deprecated_multi_crt_init(fmpz_multi_crt_t CRT); FLINT_DLL int fmpz_deprecated_multi_crt_precompute(fmpz_multi_crt_t CRT, const fmpz * moduli, slong len); FLINT_DLL int fmpz_deprecated_multi_crt_precompute_p(fmpz_multi_crt_t CRT, const fmpz * const * moduli, slong len); FLINT_DLL void fmpz_deprecated_multi_crt_precomp(fmpz_t output, const fmpz_multi_crt_t P, const fmpz * inputs); FLINT_DLL void fmpz_deprecated_multi_crt_precomp_p(fmpz_t output, const fmpz_multi_crt_t P, const fmpz * const * inputs); FLINT_DLL int fmpz_deprecated_multi_crt(fmpz_t output, const fmpz * moduli, const fmpz * values, slong len); FLINT_DLL void fmpz_deprecated_multi_crt_clear(fmpz_multi_crt_t P); FLINT_DLL slong _fmpz_deprecated_multi_crt_local_size(const fmpz_multi_crt_t CRT); FLINT_DLL void _fmpz_deprecated_multi_crt_run(fmpz * outputs, const fmpz_multi_crt_t CRT, const fmpz * inputs); FLINT_DLL void _fmpz_deprecated_multi_crt_run_p(fmpz * outputs, const fmpz_multi_crt_t CRT, const fmpz * const * inputs); /* multi mod *****************************************************************/ typedef struct { slong in_idx; slong out_idx; fmpz_t modulus; } _fmpz_multi_mod_instr; typedef struct { _fmpz_multi_mod_instr * prog; /* straight line program */ fmpz * moduli; slong moduli_count; flint_bitcnt_t min_modulus_bits; slong length; /* length of prog */ slong alloc; /* alloc of prog */ slong localsize; /* length of tmp required in _fmpz_multi_mod_precomp */ slong temp1loc; int good; /* the moduli are good for MOD, none are zero */ } fmpz_multi_mod_struct; typedef fmpz_multi_mod_struct fmpz_multi_mod_t[1]; FLINT_DLL void fmpz_multi_mod_init(fmpz_multi_mod_t P); FLINT_DLL void fmpz_multi_mod_clear(fmpz_multi_mod_t P); FLINT_DLL int fmpz_multi_mod_precompute(fmpz_multi_mod_t P, const fmpz * f, slong r); FLINT_DLL void fmpz_multi_mod_precomp(fmpz * outputs, const fmpz_multi_mod_t P, const fmpz_t input, int sign); FLINT_DLL void _fmpz_multi_mod_precomp(fmpz * outputs, const fmpz_multi_mod_t P, const fmpz_t input, int sign, fmpz * tmp); /* multi mod/multi CRT ui ****************************************************/ typedef struct { nmod_t mod; mp_limb_t i0, i1, i2; } crt_lut_entry; typedef struct { nmod_t mod; nmod_t mod0, mod1, mod2; } mod_lut_entry; typedef struct { fmpz_multi_CRT_t crt_P; fmpz_multi_mod_t mod_P; mp_limb_t * packed_multipliers; slong * step; slong * crt_offsets; slong crt_offsets_alloc; slong * mod_offsets; slong mod_offsets_alloc; crt_lut_entry * crt_lu; slong crt_lu_alloc; slong crt_klen; mod_lut_entry * mod_lu; slong mod_lu_alloc; slong mod_klen; slong num_primes; } fmpz_comb_struct; typedef fmpz_comb_struct fmpz_comb_t[1]; typedef struct { slong Alen, Tlen; fmpz * A, * T; } fmpz_comb_temp_struct; typedef fmpz_comb_temp_struct fmpz_comb_temp_t[1]; FLINT_DLL void fmpz_comb_temp_init(fmpz_comb_temp_t CT, const fmpz_comb_t C); FLINT_DLL void fmpz_comb_temp_clear(fmpz_comb_temp_t CT); FLINT_DLL void fmpz_comb_init(fmpz_comb_t C, mp_srcptr primes, slong num_primes); FLINT_DLL void fmpz_comb_clear(fmpz_comb_t C); FLINT_DLL void fmpz_multi_mod_ui(mp_limb_t * out, const fmpz_t in, const fmpz_comb_t C, fmpz_comb_temp_t CT); FLINT_DLL void fmpz_multi_CRT_ui(fmpz_t output, mp_srcptr residues, const fmpz_comb_t comb, fmpz_comb_temp_t temp, int sign); /*****************************************************************************/ FLINT_DLL mp_limb_t fmpz_abs_ubound_ui_2exp(slong * exp, const fmpz_t x, int bits); FLINT_DLL mp_limb_t fmpz_abs_lbound_ui_2exp(slong * exp, const fmpz_t x, int bits); FLINT_DLL void fmpz_lucas_chain(fmpz_t Vm, fmpz_t Vm1, const fmpz_t A, const fmpz_t m, const fmpz_t n); FLINT_DLL void fmpz_lucas_chain_full(fmpz_t Vm, fmpz_t Vm1, const fmpz_t A, const fmpz_t B, const fmpz_t m, const fmpz_t n); FLINT_DLL void fmpz_lucas_chain_double(fmpz_t U2m, fmpz_t U2m1, const fmpz_t Um, const fmpz_t Um1, const fmpz_t A, const fmpz_t B, const fmpz_t n); FLINT_DLL void fmpz_lucas_chain_add(fmpz_t Umn, fmpz_t Umn1, const fmpz_t Um, const fmpz_t Um1, const fmpz_t Un, const fmpz_t Un1, const fmpz_t A, const fmpz_t B, const fmpz_t n); FLINT_DLL void fmpz_lucas_chain_mul(fmpz_t Ukm, fmpz_t Ukm1, const fmpz_t Um, const fmpz_t Um1, const fmpz_t A, const fmpz_t B, const fmpz_t k, const fmpz_t n); FLINT_DLL void fmpz_lucas_chain_VtoU(fmpz_t Um, fmpz_t Um1, const fmpz_t Vm, const fmpz_t Vm1, const fmpz_t A, const fmpz_t B, const fmpz_t Dinv, const fmpz_t n); FLINT_DLL int fmpz_is_probabprime_lucas(const fmpz_t n); FLINT_DLL int fmpz_is_probabprime_BPSW(const fmpz_t n); FLINT_DLL int fmpz_is_strong_probabprime(const fmpz_t n, const fmpz_t a); FLINT_DLL int fmpz_is_probabprime(const fmpz_t p); FLINT_DLL int fmpz_is_prime_pseudosquare(const fmpz_t n); FLINT_DLL void _fmpz_nm1_trial_factors(const fmpz_t n, mp_ptr pm1, slong * num_pm1, ulong limit); FLINT_DLL int fmpz_is_prime_pocklington(fmpz_t F, fmpz_t R, const fmpz_t n, mp_ptr pm1, slong num_pm1); FLINT_DLL void _fmpz_np1_trial_factors(const fmpz_t n, mp_ptr pp1, slong * num_pp1, ulong limit); FLINT_DLL int fmpz_is_prime_morrison(fmpz_t F, fmpz_t R, const fmpz_t n, mp_ptr pm1, slong num_pm1); FLINT_DLL int fmpz_is_prime(const fmpz_t p); FLINT_DLL int fmpz_divisor_in_residue_class_lenstra(fmpz_t fac, const fmpz_t n, const fmpz_t r, const fmpz_t s); FLINT_DLL void fmpz_nextprime(fmpz_t res, const fmpz_t n, int proved); /* Primorials */ FLINT_DLL void fmpz_primorial(fmpz_t res, ulong n); /* Multiplicative functions */ FLINT_DLL void fmpz_euler_phi(fmpz_t res, const fmpz_t n); FLINT_DLL int fmpz_moebius_mu(const fmpz_t n); FLINT_DLL void fmpz_divisor_sigma(fmpz_t res, ulong k, const fmpz_t n); /* Functions that should be in ulong extras */ FLINT_DLL ulong n_powmod2_fmpz_preinv(ulong a, const fmpz_t exp, ulong n, ulong ninv); FMPZ_INLINE mp_limb_t nmod_pow_fmpz(mp_limb_t a, const fmpz_t exp, nmod_t mod) { return n_powmod2_fmpz_preinv(a, exp, mod.n, mod.ninv); } /* Inlines *******************************************************************/ FLINT_DLL fmpz * __new_fmpz(); FLINT_DLL void __free_fmpz(fmpz * f); FLINT_DLL void __fmpz_set_si(fmpz_t f, slong val); FLINT_DLL void __fmpz_set_ui(fmpz_t f, ulong val); FLINT_DLL void __fmpz_init(fmpz_t f); FLINT_DLL void __fmpz_init_set_ui(fmpz_t f, ulong g); FLINT_DLL void __fmpz_clear(fmpz_t f); FLINT_DLL int __fmpz_lt(fmpz_t f, fmpz_t g); FLINT_DLL int __fmpz_gt(fmpz_t f, fmpz_t g); FLINT_DLL int __fmpz_lte(fmpz_t f, fmpz_t g); FLINT_DLL int __fmpz_gte(fmpz_t f, fmpz_t g); FLINT_DLL int __fmpz_eq(fmpz_t f, fmpz_t g); FLINT_DLL int __fmpz_neq(fmpz_t f, fmpz_t g); FLINT_DLL void __fmpz_init_set(fmpz_t f, const fmpz_t g); FLINT_DLL void __fmpz_neg(fmpz_t f1, const fmpz_t f2); #ifdef __cplusplus } #endif /* Copyright (C) 2011 Fredrik Johansson This file is part of FLINT. FLINT is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See <https://www.gnu.org/licenses/>. */ #ifndef FMPZ_FACTOR_H #define FMPZ_FACTOR_H #ifdef FMPZ_FACTOR_INLINES_C #define FMPZ_FACTOR_INLINE FLINT_DLL #else #define FMPZ_FACTOR_INLINE static __inline__ #endif #include <gmp.h> #ifdef __cplusplus extern "C" { #endif typedef struct { int sign; fmpz * p; ulong * exp; slong alloc; slong num; } fmpz_factor_struct; typedef fmpz_factor_struct fmpz_factor_t[1]; /* Utility functions *********************************************************/ FLINT_DLL void fmpz_factor_init(fmpz_factor_t factor); FLINT_DLL void fmpz_factor_clear(fmpz_factor_t factor); FLINT_DLL void fmpz_factor_print(const fmpz_factor_t factor); FLINT_DLL void _fmpz_factor_fit_length(fmpz_factor_t factor, slong len); FLINT_DLL void _fmpz_factor_append_ui(fmpz_factor_t factor, mp_limb_t p, ulong exp); FLINT_DLL void _fmpz_factor_append(fmpz_factor_t factor, const fmpz_t p, ulong exp); FLINT_DLL void _fmpz_factor_set_length(fmpz_factor_t factor, slong newlen); FLINT_DLL void _fmpz_factor_concat(fmpz_factor_t factor1, fmpz_factor_t factor2, ulong exp); /* Factoring *****************************************************************/ FLINT_DLL void _fmpz_factor_extend_factor_ui(fmpz_factor_t factor, mp_limb_t n); FLINT_DLL int fmpz_factor_trial_range(fmpz_factor_t factor, const fmpz_t n, ulong start, ulong num_primes); FLINT_DLL int fmpz_factor_trial(fmpz_factor_t factor, const fmpz_t n, slong num_primes); FLINT_DLL void fmpz_factor(fmpz_factor_t factor, const fmpz_t n); FLINT_DLL void fmpz_factor_no_trial(fmpz_factor_t factor, const fmpz_t n); FLINT_DLL int fmpz_factor_smooth(fmpz_factor_t factor, const fmpz_t n, slong bits, int proved); FLINT_DLL void fmpz_factor_si(fmpz_factor_t factor, slong n); FLINT_DLL int fmpz_factor_pp1(fmpz_t factor, const fmpz_t n, ulong B1, ulong B2_sqrt, ulong c); FLINT_DLL void fmpz_factor_refine(fmpz_factor_t res, const fmpz_factor_t f); FLINT_DLL void flint_mpn_sqr_and_add_a(mp_ptr y, mp_ptr a, mp_ptr n, mp_limb_t n_size, mp_ptr ninv, mp_limb_t normbits); FLINT_DLL int flint_mpn_factor_pollard_brent_single(mp_ptr factor, mp_ptr n, mp_ptr ninv, mp_ptr a, mp_ptr y, mp_limb_t n_size, mp_limb_t normbits, mp_limb_t max_iters); FLINT_DLL int fmpz_factor_pollard_brent_single(fmpz_t p_factor, fmpz_t n_in, fmpz_t yi, fmpz_t ai, mp_limb_t max_iters); FLINT_DLL int fmpz_factor_pollard_brent(fmpz_t factor, flint_rand_t state, fmpz_t n, mp_limb_t max_tries, mp_limb_t max_iters); /* Expansion *****************************************************************/ FLINT_DLL void fmpz_factor_expand_iterative(fmpz_t n, const fmpz_factor_t factor); FLINT_DLL void fmpz_factor_expand_multiexp(fmpz_t n, const fmpz_factor_t factor); FLINT_DLL void fmpz_factor_expand(fmpz_t n, const fmpz_factor_t factor); /* Multiplicative functions **************************************************/ FLINT_DLL void fmpz_factor_euler_phi(fmpz_t res, const fmpz_factor_t fac); FLINT_DLL int fmpz_factor_moebius_mu(const fmpz_factor_t fac); FLINT_DLL void fmpz_factor_divisor_sigma(fmpz_t res, ulong k, const fmpz_factor_t fac); /* ECM Factoring functions ***************************************************/ typedef struct ecm_s { mp_ptr t, u, v, w; /* temp variables */ mp_ptr x, z; /* the coordinates */ mp_ptr a24; /* value (a + 2)/4 */ mp_ptr ninv; /* invere of n */ mp_ptr one; /* one shifted */ unsigned char *GCD_table; /* checks whether baby step int is coprime to Primorial or not */ unsigned char **prime_table; mp_limb_t n_size; mp_limb_t normbits; } ecm_s; typedef ecm_s ecm_t[1]; FLINT_DLL void fmpz_factor_ecm_init(ecm_t ecm_inf, mp_limb_t sz); FLINT_DLL void fmpz_factor_ecm_clear(ecm_t ecm_inf); FLINT_DLL void fmpz_factor_ecm_addmod(mp_ptr a, mp_ptr b, mp_ptr c, mp_ptr n, mp_limb_t n_size); FLINT_DLL void fmpz_factor_ecm_submod(mp_ptr x, mp_ptr a, mp_ptr b, mp_ptr n, mp_limb_t n_size); FLINT_DLL void fmpz_factor_ecm_double(mp_ptr x, mp_ptr z, mp_ptr x0, mp_ptr z0, mp_ptr n, ecm_t ecm_inf); FLINT_DLL void fmpz_factor_ecm_add(mp_ptr x, mp_ptr z, mp_ptr x1, mp_ptr z1, mp_ptr x2, mp_ptr z2, mp_ptr x0, mp_ptr z0, mp_ptr n, ecm_t ecm_inf); FLINT_DLL void fmpz_factor_ecm_mul_montgomery_ladder(mp_ptr x, mp_ptr z, mp_ptr x0, mp_ptr z0, mp_limb_t k, mp_ptr n, ecm_t ecm_inf); FLINT_DLL int fmpz_factor_ecm_select_curve(mp_ptr f, mp_ptr sig, mp_ptr n, ecm_t ecm_inf); FLINT_DLL int fmpz_factor_ecm_stage_I(mp_ptr f, const mp_limb_t *prime_array, mp_limb_t num, mp_limb_t B1, mp_ptr n, ecm_t ecm_inf); FLINT_DLL int fmpz_factor_ecm_stage_II(mp_ptr f, mp_limb_t B1, mp_limb_t B2, mp_limb_t P, mp_ptr n, ecm_t ecm_inf); FLINT_DLL int fmpz_factor_ecm(fmpz_t f, mp_limb_t curves, mp_limb_t B1, mp_limb_t B2, flint_rand_t state, const fmpz_t n_in); /* Inlines *******************************************************************/ FLINT_DLL void fmpz_factor_get_fmpz(fmpz_t z, const fmpz_factor_t factor, slong i); #ifdef __cplusplus } #endif #endif #endif #undef clrbit /* no idea where these are coming from */ #undef setbit // TODO functions for addmul? inhomogeneous addmul? // TODO use evaluate_n in immediate functions? // TODO fmpz_abs_ubound_ui_2exp, lbound // TODO cmpabs // TODO xgcd_partial namespace flint { FLINT_DEFINE_BINOP(cdiv_q) FLINT_DEFINE_BINOP(fdiv_r) FLINT_DEFINE_BINOP(tdiv_q) FLINT_DEFINE_BINOP(fdiv_r_2exp) FLINT_DEFINE_BINOP(tdiv_q_2exp) FLINT_DEFINE_UNOP(fac) FLINT_DEFINE_UNOP(fib) FLINT_DEFINE_BINOP(rfac) FLINT_DEFINE_BINOP(bin) FLINT_DEFINE_BINOP(gcd) FLINT_DEFINE_BINOP(lcm) FLINT_DEFINE_BINOP(invmod) FLINT_DEFINE_BINOP(negmod) FLINT_DEFINE_THREEARY(mul2) FLINT_DEFINE_THREEARY(divexact2) FLINT_DEFINE_THREEARY(powm) FLINT_DEFINE_THREEARY(mul_tdiv_q_2exp) FLINT_DEFINE_BINOP(fdiv_qr) FLINT_DEFINE_BINOP(tdiv_qr) FLINT_DEFINE_BINOP(sqrtmod) FLINT_DEFINE_UNOP(sqrtrem) FLINT_DEFINE_BINOP(gcdinv) FLINT_DEFINE_BINOP(xgcd) FLINT_DEFINE_BINOP(remove) FLINT_DEFINE_FIVEARY(fmpzxx_bit_unpack) FLINT_DEFINE_THREEARY(fmpzxx_bit_unpack_unsigned) namespace mp { template<class Out, class T1, class T2 = void, class T3 = void, class T4 = void> struct enable_all_fmpzxx; } template<class Operation, class Data> class fmpzxx_expression : public expression<derived_wrapper<fmpzxx_expression>, Operation, Data> { public: typedef expression<derived_wrapper< ::flint::fmpzxx_expression>, Operation, Data> base_t; FLINTXX_DEFINE_BASICS(fmpzxx_expression) FLINTXX_DEFINE_CTORS(fmpzxx_expression) FLINTXX_DEFINE_C_REF(fmpzxx_expression, fmpz, _fmpz) // these only make sense with fmpzxx FLINTXX_DEFINE_RANDFUNC(fmpz, randbits) FLINTXX_DEFINE_RANDFUNC(fmpz, randtest) FLINTXX_DEFINE_RANDFUNC(fmpz, randtest_unsigned) FLINTXX_DEFINE_RANDFUNC(fmpz, randtest_not_zero) template<class Fmpz> static fmpzxx_expression randm(frandxx& state, const Fmpz& m) { fmpzxx_expression res; fmpz_randm(res._fmpz(), state._data(), m.evaluate()._fmpz()); return res; } template<class Fmpz> static fmpzxx_expression randtest_mod(frandxx& state, const Fmpz& m) { fmpzxx_expression res; fmpz_randtest_mod(res._fmpz(), state._data(), m.evaluate()._fmpz()); return res; } template<class Fmpz> static fmpzxx_expression randtest_mod_signed(frandxx& state, const Fmpz& m) { fmpzxx_expression res; fmpz_randtest_mod_signed(res._fmpz(), state._data(), m.evaluate()._fmpz()); return res; } // TODO would these make more sense static? void set_ui_smod(mp_limb_t x, mp_limb_t m) { fmpz_set_ui_smod(this->_fmpz(), x, m); } void set_uiui(mp_limb_t hi, mp_limb_t lo) { fmpz_set_uiui(this->_fmpz(), hi, lo); } void neg_uiui(mp_limb_t hi, mp_limb_t lo) { fmpz_neg_uiui(this->_fmpz(), hi, lo); } // these only make sense with fmpzxx/fmpzxx_ref void clrbit(ulong i) {fmpz_clrbit(_fmpz(), i);} void combit(ulong i) {fmpz_combit(_fmpz(), i);} void setbit(ulong i) {fmpz_setbit(_fmpz(), i);} void set_zero() {fmpz_zero(_fmpz());} void set_one() {fmpz_one(_fmpz());} // These make sense with all expressions, but cause evaluation double get_d_2exp(slong& exp) const { return fmpz_get_d_2exp(&exp, this->evaluate()._fmpz()); } bool is_zero() const { return fmpz_is_zero(this->evaluate()._fmpz()); } bool is_one() const { return fmpz_is_one(this->evaluate()._fmpz()); } bool is_pm1() const { return fmpz_is_pm1(this->evaluate()._fmpz()); } bool is_even() const { return fmpz_is_even(this->evaluate()._fmpz()); } bool is_odd() const { return fmpz_is_odd(this->evaluate()._fmpz()); } bool is_square() const { return fmpz_is_square(this->evaluate()._fmpz()); } int popcnt() const { return fmpz_popcnt(this->evaluate()._fmpz()); } bool is_probabprime() const { return fmpz_is_probabprime(this->evaluate()._fmpz()); } bool is_prime_pseudosquare() const { return fmpz_is_prime_pseudosquare(this->evaluate()._fmpz()); } bool abs_fits_ui() const { return fmpz_abs_fits_ui(this->evaluate()._fmpz()); } bool fits_si() const { return fmpz_fits_si(this->evaluate()._fmpz()); } bool tstbit(ulong i) const { return fmpz_tstbit(this->evaluate()._fmpz(), i); } template<class T2> typename mp::enable_all_fmpzxx<bool, T2>::type divisible(const T2& t2) const { return fmpz_divisible(this->evaluate()._fmpz(), t2.evaluate()._fmpz()); } template<class T2> typename mp::enable_if<traits::fits_into_slong<T2>, bool>::type divisible(const T2& t2) const { return fmpz_divisible_si(this->evaluate()._fmpz(), t2); } template<class Fmpz2> typename mp::enable_all_fmpzxx<slong, Fmpz2>::type clog(const Fmpz2& b) const { return fmpz_clog(this->evaluate()._fmpz(), b.evaluate()._fmpz()); } template<class Int> typename mp::enable_if<traits::is_unsigned_integer<Int>, slong>::type clog(Int b) const { return fmpz_clog_ui(this->evaluate()._fmpz(), b); } template<class Fmpz2> typename mp::enable_all_fmpzxx<slong, Fmpz2>::type flog(const Fmpz2& b) const { return fmpz_flog(this->evaluate()._fmpz(), b.evaluate()._fmpz()); } template<class Int> typename mp::enable_if<traits::is_unsigned_integer<Int>, slong>::type flog(Int b) const { return fmpz_flog_ui(this->evaluate()._fmpz(), b); } double dlog() const { return fmpz_dlog(this->evaluate()._fmpz()); } template<class Fmpz2> typename mp::enable_all_fmpzxx<int, Fmpz2>::type jacobi(const Fmpz2& p) const { return fmpz_jacobi(this->evaluate()._fmpz(), p.evaluate()._fmpz()); } size_t sizeinbase(int b) const {return fmpz_sizeinbase(this->evaluate()._fmpz(), b);} flint_bitcnt_t bits() const {return fmpz_bits(this->evaluate()._fmpz());} flint_bitcnt_t size() const {return fmpz_size(this->evaluate()._fmpz());} flint_bitcnt_t val2() const {return fmpz_val2(this->evaluate()._fmpz());} int sgn() const {return fmpz_sgn(this->evaluate()._fmpz());} // lazy function forwarding FLINTXX_DEFINE_MEMBER_3OP(divexact2) FLINTXX_DEFINE_MEMBER_3OP(mul2) FLINTXX_DEFINE_MEMBER_3OP(mul_tdiv_q_2exp) FLINTXX_DEFINE_MEMBER_3OP(powm) FLINTXX_DEFINE_MEMBER_BINOP(cdiv_q) FLINTXX_DEFINE_MEMBER_BINOP(divexact) FLINTXX_DEFINE_MEMBER_BINOP(fdiv_qr) FLINTXX_DEFINE_MEMBER_BINOP(fdiv_r) FLINTXX_DEFINE_MEMBER_BINOP(fdiv_r_2exp) FLINTXX_DEFINE_MEMBER_BINOP(gcd) FLINTXX_DEFINE_MEMBER_BINOP(gcdinv) FLINTXX_DEFINE_MEMBER_BINOP(invmod) FLINTXX_DEFINE_MEMBER_BINOP(lcm) FLINTXX_DEFINE_MEMBER_BINOP(negmod) FLINTXX_DEFINE_MEMBER_BINOP(pow) FLINTXX_DEFINE_MEMBER_BINOP(remove) FLINTXX_DEFINE_MEMBER_BINOP(rfac) FLINTXX_DEFINE_MEMBER_BINOP(root) FLINTXX_DEFINE_MEMBER_BINOP(sqrtmod) FLINTXX_DEFINE_MEMBER_BINOP(tdiv_q) FLINTXX_DEFINE_MEMBER_BINOP(tdiv_q_2exp) FLINTXX_DEFINE_MEMBER_BINOP(tdiv_qr) FLINTXX_DEFINE_MEMBER_BINOP(xgcd) FLINTXX_DEFINE_MEMBER_UNOP(abs) FLINTXX_DEFINE_MEMBER_UNOP(sqrt) // FLINTXX_DEFINE_MEMBER_UNOP(sqrtrem) // TODO FLINTXX_DEFINE_MEMBER_5OP(CRT) template<class Arg1, class Arg2> static FLINT_FIVEARY_ENABLE_RETTYPE(fmpzxx_bit_unpack, Arg1, Arg2, flint_bitcnt_t, int, bool) bit_unpack(const Arg1& arr, const Arg2& bits, flint_bitcnt_t shift = 0, int negate = 0, bool borrow = false) { return fmpzxx_bit_unpack(arr, bits, shift, negate, borrow); } template<class Arg1, class Arg2> static FLINT_THREEARY_ENABLE_RETTYPE(fmpzxx_bit_unpack_unsigned, Arg1, Arg2, flint_bitcnt_t) bit_unpack_unsigned(const Arg1& arr, const Arg2& bits, flint_bitcnt_t shift = 0) { return fmpzxx_bit_unpack_unsigned(arr, bits, shift); } }; namespace detail { struct fmpz_data; } typedef fmpzxx_expression<operations::immediate, detail::fmpz_data> fmpzxx; typedef fmpzxx_expression<operations::immediate, flint_classes::ref_data<fmpzxx, fmpz> > fmpzxx_ref; typedef fmpzxx_expression<operations::immediate, flint_classes::srcref_data<fmpzxx, fmpzxx_ref, fmpz> > fmpzxx_srcref; namespace detail { struct fmpz_data { typedef fmpz_t& data_ref_t; typedef const fmpz_t& data_srcref_t; fmpz_t inner; fmpz_data() {fmpz_init(inner);} ~fmpz_data() {fmpz_clear(inner);} fmpz_data(const fmpz_data& o) {fmpz_init_set(inner, o.inner);} template<class T> fmpz_data(const T& t) { init(t); } template<class T> typename mp::enable_if<traits::is_unsigned_integer<T> >::type init(T t) { fmpz_init_set_ui(inner, t); } template<class T> typename mp::enable_if<traits::is_signed_integer<T> >::type init(T t) { fmpz_init(inner); fmpz_set_si(inner, t); } void init(double d) { fmpz_init(inner); fmpz_set_d(inner, d); } void init(const char* str) { fmpz_init(inner); fmpz_set_str(inner, str, 10); } void init(const fmpzxx_srcref& r) { fmpz_init_set(inner, r._fmpz()); } }; } // detail /////////////////////////////////////////////////////////////////// // HELPERS /////////////////////////////////////////////////////////////////// namespace traits { template<class T> struct is_fmpzxx : mp::or_< traits::is_T_expr<T, fmpzxx>, flint_classes::is_source<fmpzxx, T> > { }; } // traits namespace mp { template<class T1, class T2 = void, class T3 = void, class T4 = void> struct all_fmpzxx : mp::and_<all_fmpzxx<T1>, all_fmpzxx<T2, T3, T4> > { }; template<class T> struct all_fmpzxx<T, void, void, void> : traits::is_fmpzxx<T> { }; template<class Out, class T1, class T2, class T3, class T4> struct enable_all_fmpzxx : mp::enable_if<all_fmpzxx<T1, T2, T3, T4>, Out> { }; } // mp /////////////////////////////////////////////////////////////////// // RULES /////////////////////////////////////////////////////////////////// namespace rules { #define FMPZXX_COND_S FLINTXX_COND_S(fmpzxx) #define FMPZXX_COND_T FLINTXX_COND_T(fmpzxx) FLINT_DEFINE_DOIT_COND2(assignment, FMPZXX_COND_T, FMPZXX_COND_S, fmpz_set(to._fmpz(), from._fmpz())) FLINT_DEFINE_DOIT_COND2(assignment, FMPZXX_COND_T, traits::is_unsigned_integer, fmpz_set_ui(to._fmpz(), from)) FLINT_DEFINE_DOIT_COND2(assignment, FMPZXX_COND_T, traits::is_signed_integer, fmpz_set_si(to._fmpz(), from)) FLINTXX_DEFINE_CMP(fmpzxx, fmpz_cmp(e1._fmpz(), e2._fmpz())) template<class T, class U> struct cmp<T, U, typename mp::enable_if<mp::and_< FMPZXX_COND_S<T>, traits::is_signed_integer<U> > >::type> { static int get(const T& v, const U& t) { return fmpz_cmp_si(v._fmpz(), t); } }; template<class T> struct cmp<fmpzxx, T, typename mp::enable_if<traits::is_unsigned_integer<T> >::type> { static int get(const fmpzxx& v, const T& t) { return fmpz_cmp_ui(v._fmpz(), t); } }; FLINTXX_DEFINE_ASSIGN_STR(fmpzxx, fmpz_set_str(to._fmpz(), from, 10)) FLINTXX_DEFINE_TO_STR(fmpzxx, fmpz_get_str(0, base, from._fmpz())) FLINTXX_DEFINE_SWAP(fmpzxx, fmpz_swap(e1._fmpz(), e2._fmpz())) FLINT_DEFINE_PRINT_COND(FMPZXX_COND_S, fmpz_fprint(to, from._fmpz())) FLINT_DEFINE_READ_COND(FMPZXX_COND_T, fmpz_fread(from, to._fmpz())) FLINT_DEFINE_GET_COND(conversion, slong, FMPZXX_COND_S, fmpz_get_si(from._fmpz())) FLINT_DEFINE_GET_COND(conversion, ulong, FMPZXX_COND_S, fmpz_get_ui(from._fmpz())) FLINT_DEFINE_GET_COND(conversion, double, FMPZXX_COND_S, fmpz_get_d(from._fmpz())) FLINT_DEFINE_BINARY_EXPR_COND2(plus, fmpzxx, FMPZXX_COND_S, FMPZXX_COND_S, fmpz_add(to._fmpz(), e1._fmpz(), e2._fmpz())) FLINT_DEFINE_CBINARY_EXPR_COND2(plus, fmpzxx, FMPZXX_COND_S, traits::is_unsigned_integer, fmpz_add_ui(to._fmpz(), e1._fmpz(), e2)) FLINT_DEFINE_CBINARY_EXPR_COND2(plus, fmpzxx, FMPZXX_COND_S, traits::is_signed_integer, fmpz_add_si(to._fmpz(), e1._fmpz(), e2)) FLINT_DEFINE_CBINARY_EXPR_COND2(times, fmpzxx, FMPZXX_COND_S, FMPZXX_COND_S, fmpz_mul(to._fmpz(), e1._fmpz(), e2._fmpz())) FLINT_DEFINE_CBINARY_EXPR_COND2(times, fmpzxx, FMPZXX_COND_S, traits::is_unsigned_integer, fmpz_mul_ui(to._fmpz(), e1._fmpz(), e2)) FLINT_DEFINE_CBINARY_EXPR_COND2(times, fmpzxx, FMPZXX_COND_S, traits::is_signed_integer, fmpz_mul_si(to._fmpz(), e1._fmpz(), e2)) FLINT_DEFINE_BINARY_EXPR_COND2(minus, fmpzxx, FMPZXX_COND_S, FMPZXX_COND_S, fmpz_sub(to._fmpz(), e1._fmpz(), e2._fmpz())) FLINT_DEFINE_BINARY_EXPR_COND2(minus, fmpzxx, FMPZXX_COND_S, traits::is_unsigned_integer, fmpz_sub_ui(to._fmpz(), e1._fmpz(), e2)) FLINT_DEFINE_BINARY_EXPR_COND2(minus, fmpzxx, FMPZXX_COND_S, traits::is_signed_integer, fmpz_sub_si(to._fmpz(), e1._fmpz(), e2)) FLINT_DEFINE_BINARY_EXPR_COND2(divided_by, fmpzxx, FMPZXX_COND_S, FMPZXX_COND_S, fmpz_fdiv_q(to._fmpz(), e1._fmpz(), e2._fmpz())) FLINT_DEFINE_BINARY_EXPR_COND2(divided_by, fmpzxx, FMPZXX_COND_S, traits::is_unsigned_integer, fmpz_fdiv_q_ui(to._fmpz(), e1._fmpz(), e2)) FLINT_DEFINE_BINARY_EXPR_COND2(divided_by, fmpzxx, FMPZXX_COND_S, traits::is_signed_integer, fmpz_fdiv_q_si(to._fmpz(), e1._fmpz(), e2)) // TODO this interpretation of mod is not the same as for builtin types! FLINT_DEFINE_BINARY_EXPR_COND2(modulo, fmpzxx, FMPZXX_COND_S, FMPZXX_COND_S, fmpz_mod(to._fmpz(), e1._fmpz(), e2._fmpz())) FLINT_DEFINE_BINARY_EXPR_COND2(modulo, fmpzxx, FMPZXX_COND_S, traits::is_unsigned_integer, fmpz_mod_ui(to._fmpz(), e1._fmpz(), e2)) FLINT_DEFINE_BINARY_EXPR_COND2(binary_and, fmpzxx, FMPZXX_COND_S, FMPZXX_COND_S, fmpz_and(to._fmpz(), e1._fmpz(), e2._fmpz())) FLINT_DEFINE_BINARY_EXPR_COND2(binary_or, fmpzxx, FMPZXX_COND_S, FMPZXX_COND_S, fmpz_or(to._fmpz(), e1._fmpz(), e2._fmpz())) FLINT_DEFINE_BINARY_EXPR_COND2(binary_xor, fmpzxx, FMPZXX_COND_S, FMPZXX_COND_S, fmpz_xor(to._fmpz(), e1._fmpz(), e2._fmpz())) FLINT_DEFINE_UNARY_EXPR_COND(negate, fmpzxx, FMPZXX_COND_S, fmpz_neg(to._fmpz(), from._fmpz())) FLINT_DEFINE_UNARY_EXPR_COND(complement, fmpzxx, FMPZXX_COND_S, fmpz_complement(to._fmpz(), from._fmpz())) namespace rdetail { template<class Fmpz1, class Fmpz2, class T> void fmpzxx_shift(Fmpz1& to, const Fmpz2& from, T howmuch) { if(howmuch < 0) fmpz_fdiv_q_2exp(to._fmpz(), from._fmpz(), -howmuch); else fmpz_mul_2exp(to._fmpz(), from._fmpz(), howmuch); } } // rdetail FLINT_DEFINE_BINARY_EXPR_COND2(shift, fmpzxx, FMPZXX_COND_S, traits::is_integer, rdetail::fmpzxx_shift(to, e1, e2)) } // rules FLINTXX_DEFINE_TERNARY(fmpzxx, fmpz_addmul(to._fmpz(), e1._fmpz(), e2._fmpz()), fmpz_submul(to._fmpz(), e1._fmpz(), e2._fmpz()), FLINTXX_UNADORNED_MAKETYPES) /////////////////////////////////////////////////////////////////////////// // FUNCTIONS /////////////////////////////////////////////////////////////////////////// // These functions evaluate immediately, and (often) do not yield fmpzxxs template<class T1, class T2> inline typename mp::enable_all_fmpzxx<bool, T1>::type divisible(const T1& t1, const T2& t2) { return t1.divisible(t2); } template<class Fmpz1, class Fmpz2> inline typename mp::enable_all_fmpzxx<slong, Fmpz1>::type clog(const Fmpz1& x, const Fmpz2& b) { return x.clog(b); } template<class Fmpz1, class Fmpz2> inline typename mp::enable_all_fmpzxx<slong, Fmpz1>::type flog(const Fmpz1& x, const Fmpz2& b) { return x.flog(b); } template<class Fmpz> inline typename mp::enable_if<traits::is_fmpzxx<Fmpz>, double>::type dlog(const Fmpz& x) { return x.dlog(); } template<class Fmpz1, class Fmpz2> inline typename mp::enable_all_fmpzxx<int, Fmpz1>::type jacobi(const Fmpz1& a, const Fmpz2& p) { return a.jacobi(p); } template<class Fmpz> inline typename mp::enable_if<traits::is_fmpzxx<Fmpz>, size_t>::type sizeinbase(const Fmpz& a, int b) { return a.sizeinbase(b); } template<class Fmpz> inline typename mp::enable_if<traits::is_fmpzxx<Fmpz>, flint_bitcnt_t>::type bits(const Fmpz& a) { return a.bits(); } template<class Fmpz> inline typename mp::enable_if<traits::is_fmpzxx<Fmpz>, flint_bitcnt_t>::type val2(const Fmpz& a) { return a.val2(); } template<class Fmpz> inline typename mp::enable_if<traits::is_fmpzxx<Fmpz>, flint_bitcnt_t>::type size(const Fmpz& a) { return a.size(); } template<class Fmpz> inline typename mp::enable_if<traits::is_fmpzxx<Fmpz>, int>::type sgn(const Fmpz& a) { return a.sgn(); } template<class Fmpz> inline bool bit_pack(std::vector<mp_limb_t>& arr, flint_bitcnt_t bits, const Fmpz& coeff, flint_bitcnt_t shift = 0, int negate = 0, bool borrow = false, typename mp::enable_if<traits::is_fmpzxx<Fmpz> >::type* = 0) { return fmpz_bit_pack(&arr.front(), shift, bits, coeff.evaluate()._fmpz(), negate, borrow); } // These functions are evaluated lazily namespace rules { FLINT_DEFINE_BINARY_EXPR_COND2(rfac_op, fmpzxx, FMPZXX_COND_S, traits::is_unsigned_integer, fmpz_rfac_ui(to._fmpz(), e1._fmpz(), e2)) FLINT_DEFINE_UNARY_EXPR_COND(fac_op, fmpzxx, traits::is_unsigned_integer, fmpz_fac_ui(to._fmpz(), from)) FLINT_DEFINE_UNARY_EXPR_COND(fib_op, fmpzxx, traits::is_unsigned_integer, fmpz_fib_ui(to._fmpz(), from)) FLINT_DEFINE_BINARY_EXPR_COND2(gcd_op, fmpzxx, FMPZXX_COND_S, FMPZXX_COND_S, fmpz_gcd(to._fmpz(), e1._fmpz(), e2._fmpz())) FLINT_DEFINE_BINARY_EXPR_COND2(lcm_op, fmpzxx, FMPZXX_COND_S, FMPZXX_COND_S, fmpz_lcm(to._fmpz(), e1._fmpz(), e2._fmpz())) template<class T1, class T2> struct binary_expression< T1, typename mp::enable_if< mp::and_< traits::is_unsigned_integer<T1>, traits::is_unsigned_integer<T2> >, operations::bin_op>::type, T2> { typedef fmpzxx return_t; template<class V> static void doit(V& to, const T1& t1, const T2& t2) { fmpz_bin_uiui(to._fmpz(), t1, t2); } }; #define FMPZXX_DEFINE_DIVFUNCS(name) \ FLINT_DEFINE_BINARY_EXPR_COND2(name##_op, fmpzxx, FMPZXX_COND_S, FMPZXX_COND_S, \ fmpz_##name(to._fmpz(), e1._fmpz(), e2._fmpz())) \ FLINT_DEFINE_BINARY_EXPR_COND2(name##_op, fmpzxx, FMPZXX_COND_S, \ traits::is_signed_integer, \ fmpz_##name##_si(to._fmpz(), e1._fmpz(), e2)) \ FLINT_DEFINE_BINARY_EXPR_COND2(name##_op, fmpzxx, FMPZXX_COND_S, \ traits::is_unsigned_integer, \ fmpz_##name##_ui(to._fmpz(), e1._fmpz(), e2)) FMPZXX_DEFINE_DIVFUNCS(cdiv_q) FMPZXX_DEFINE_DIVFUNCS(tdiv_q) FMPZXX_DEFINE_DIVFUNCS(divexact) FLINT_DEFINE_BINARY_EXPR_COND2(fdiv_r_op, fmpzxx, FMPZXX_COND_S, FMPZXX_COND_S, fmpz_fdiv_r(to._fmpz(), e1._fmpz(), e2._fmpz())) FLINT_DEFINE_BINARY_EXPR_COND2(tdiv_q_2exp_op, fmpzxx, FMPZXX_COND_S, traits::is_unsigned_integer, fmpz_tdiv_q_2exp(to._fmpz(), e1._fmpz(), e2)) FLINT_DEFINE_BINARY_EXPR_COND2(fdiv_r_2exp_op, fmpzxx, FMPZXX_COND_S, traits::is_unsigned_integer, fmpz_fdiv_r_2exp(to._fmpz(), e1._fmpz(), e2)) FLINT_DEFINE_BINARY_EXPR_COND2(invmod_op, fmpzxx, FMPZXX_COND_S, FMPZXX_COND_S, fmpz_invmod(to._fmpz(), e1._fmpz(), e2._fmpz())) FLINT_DEFINE_BINARY_EXPR_COND2(negmod_op, fmpzxx, FMPZXX_COND_S, FMPZXX_COND_S, fmpz_negmod(to._fmpz(), e1._fmpz(), e2._fmpz())) FLINT_DEFINE_THREEARY_EXPR_COND3(mul2_op, fmpzxx, FMPZXX_COND_S, traits::is_unsigned_integer, traits::is_unsigned_integer, fmpz_mul2_uiui(to._fmpz(), e1._fmpz(), e2, e3)) FLINT_DEFINE_THREEARY_EXPR_COND3(divexact2_op, fmpzxx, FMPZXX_COND_S, traits::is_unsigned_integer, traits::is_unsigned_integer, fmpz_divexact2_uiui(to._fmpz(), e1._fmpz(), e2, e3)) FLINT_DEFINE_THREEARY_EXPR_COND3(powm_op, fmpzxx, FMPZXX_COND_S, traits::is_unsigned_integer, FMPZXX_COND_S, fmpz_powm_ui(to._fmpz(), e1._fmpz(), e2, e3._fmpz())) FLINT_DEFINE_THREEARY_EXPR_COND3(powm_op, fmpzxx, FMPZXX_COND_S, FMPZXX_COND_S, FMPZXX_COND_S, fmpz_powm(to._fmpz(), e1._fmpz(), e2._fmpz(), e3._fmpz())) FLINT_DEFINE_THREEARY_EXPR_COND3(mul_tdiv_q_2exp_op, fmpzxx, FMPZXX_COND_S, FMPZXX_COND_S, traits::is_unsigned_integer, fmpz_mul_tdiv_q_2exp(to._fmpz(), e1._fmpz(), e2._fmpz(), e3)) FLINT_DEFINE_THREEARY_EXPR_COND3(mul_tdiv_q_2exp_op, fmpzxx, FMPZXX_COND_S, traits::fits_into_slong, traits::is_unsigned_integer, fmpz_mul_si_tdiv_q_2exp(to._fmpz(), e1._fmpz(), e2, e3)) // TODO addmul, submul? namespace rdetail { typedef make_ltuple<mp::make_tuple<fmpzxx, fmpzxx>::type>::type fmpzxx_pair; typedef make_ltuple<mp::make_tuple<fmpzxx, fmpzxx, fmpzxx>::type>::type fmpzxx_triple; typedef make_ltuple<mp::make_tuple<bool, fmpzxx>::type>::type bool_fmpzxx_pair; } // rdetail FLINT_DEFINE_BINARY_EXPR_COND2(fdiv_qr_op, rdetail::fmpzxx_pair, FMPZXX_COND_S, FMPZXX_COND_S, fmpz_fdiv_qr(to.template get<0>()._fmpz(), to.template get<1>()._fmpz(), e1._fmpz(), e2._fmpz())) FLINT_DEFINE_BINARY_EXPR_COND2(tdiv_qr_op, rdetail::fmpzxx_pair, FMPZXX_COND_S, FMPZXX_COND_S, fmpz_tdiv_qr(to.template get<0>()._fmpz(), to.template get<1>()._fmpz(), e1._fmpz(), e2._fmpz())) FLINT_DEFINE_BINARY_EXPR_COND2(sqrtmod_op, rdetail::bool_fmpzxx_pair, FMPZXX_COND_S, FMPZXX_COND_S, to.template get<0>() = fmpz_sqrtmod( to.template get<1>()._fmpz(), e1._fmpz(), e2._fmpz())) FLINT_DEFINE_UNARY_EXPR_COND(sqrtrem_op, rdetail::fmpzxx_pair, FMPZXX_COND_S, fmpz_sqrtrem(to.template get<0>()._fmpz(), to.template get<1>()._fmpz(), from._fmpz())) FLINT_DEFINE_BINARY_EXPR_COND2(gcdinv_op, rdetail::fmpzxx_pair, FMPZXX_COND_S, FMPZXX_COND_S, fmpz_gcdinv(to.template get<0>()._fmpz(), to.template get<1>()._fmpz(), e1._fmpz(), e2._fmpz())) FLINT_DEFINE_BINARY_EXPR_COND2(xgcd_op, rdetail::fmpzxx_triple, FMPZXX_COND_S, FMPZXX_COND_S, fmpz_xgcd( to.template get<0>()._fmpz(), to.template get<1>()._fmpz(), to.template get<2>()._fmpz(), e1._fmpz(), e2._fmpz())) namespace rdetail { template<class T> struct is_mplimb_t_vec : mp::equal_types<T, std::vector<mp_limb_t> > { }; } FLINT_DEFINE_FIVEARY_EXPR_COND5(fmpzxx_bit_unpack_op, rdetail::bool_fmpzxx_pair, rdetail::is_mplimb_t_vec, traits::fits_into_flint_bitcnt_t, traits::fits_into_flint_bitcnt_t, traits::is_integer, tools::is_bool, to.template get<0>() = fmpz_bit_unpack(to.template get<1>()._fmpz(), &e1.front(), e3, e2, e4, e5)) FLINT_DEFINE_THREEARY_EXPR_COND3(fmpzxx_bit_unpack_unsigned_op, fmpzxx, rdetail::is_mplimb_t_vec, traits::fits_into_flint_bitcnt_t, traits::fits_into_flint_bitcnt_t, fmpz_bit_unpack_unsigned(to._fmpz(), &e1.front(), e3, e2)) // standard math functions (c/f stdmath.h) FLINT_DEFINE_BINARY_EXPR_COND2(pow_op, fmpzxx, FMPZXX_COND_S, traits::is_unsigned_integer, fmpz_pow_ui(to._fmpz(), e1._fmpz(), e2)) FLINT_DEFINE_BINARY_EXPR_COND2(root_op, fmpzxx, FMPZXX_COND_S, traits::fits_into_slong, fmpz_root(to._fmpz(), e1._fmpz(), e2)) FLINT_DEFINE_UNARY_EXPR_COND(sqrt_op, fmpzxx, FMPZXX_COND_S, fmpz_sqrt(to._fmpz(), from._fmpz())) FLINT_DEFINE_UNARY_EXPR_COND(abs_op, fmpzxx, FMPZXX_COND_S, fmpz_abs(to._fmpz(), from._fmpz())) namespace rdetail { typedef make_ltuple<mp::make_tuple<slong, fmpzxx>::type>::type slong_fmpzxx_pair; } // rdetail FLINT_DEFINE_BINARY_EXPR_COND2(remove_op, rdetail::slong_fmpzxx_pair, FMPZXX_COND_S, FMPZXX_COND_S, to.template get<0>() = fmpz_remove(to.template get<1>()._fmpz(), e1._fmpz(), e2._fmpz())) } // rules // chinese remaindering // TODO should this use nmod? class fmpz_combxx { private: fmpz_comb_t comb; mutable fmpz_comb_temp_t tmp; // not copyable fmpz_combxx(const fmpz_combxx&); public: fmpz_combxx(const std::vector<mp_limb_t>& v) { fmpz_comb_init(comb, &v.front(), v.size()); fmpz_comb_temp_init(tmp, comb); } ~fmpz_combxx() { fmpz_comb_temp_clear(tmp); fmpz_comb_clear(comb); } const fmpz_comb_t& _comb() const {return comb;} fmpz_comb_temp_t& _temp() const {return tmp;} }; // TODO make lazy somehow? template<class Fmpz> inline typename mp::enable_if<traits::is_fmpzxx<Fmpz> >::type multi_mod(std::vector<mp_limb_t>& out, const Fmpz& in, const fmpz_combxx& comb) { fmpz_multi_mod_ui(&out.front(), in.evaluate()._fmpz(), comb._comb(), comb._temp()); } namespace rules { FLINT_DEFINE_FIVEARY_EXPR_COND5(CRT_op, fmpzxx, FMPZXX_COND_S, FMPZXX_COND_S, traits::is_unsigned_integer, traits::is_unsigned_integer, tools::is_bool, fmpz_CRT_ui(to._fmpz(), e1._fmpz(), e2._fmpz(), e3, e4, e5)) FLINT_DEFINE_THREEARY_EXPR(multi_CRT_op, fmpzxx, std::vector<mp_limb_t>, fmpz_combxx, bool, fmpz_multi_CRT_ui(to._fmpz(), &e1.front(), e2._comb(), e2._temp(), e3)) } // rules } // flint /* Copyright (C) 2013 Tom Bachmann This file is part of FLINT. FLINT is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See <https://www.gnu.org/licenses/>. */ #ifndef FMPZ_FACTORXX_H #define FMPZ_FACTORXX_H /* Copyright (C) 2010 William Hart Copyright (C) 2010 Sebastian Pancratz This file is part of FLINT. FLINT is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See <https://www.gnu.org/licenses/>. */ #ifndef FMPZ_VEC_H #define FMPZ_VEC_H #ifdef FMPZ_VEC_INLINES_C #define FMPZ_VEC_INLINE FLINT_DLL #else #define FMPZ_VEC_INLINE static __inline__ #endif #include <gmp.h> /* Copyright (C) 2010 William Hart Copyright (C) 2014 Abhinav Baid This file is part of FLINT. FLINT is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See <https://www.gnu.org/licenses/>. */ #ifndef MPF_VEC_H #define MPF_VEC_H #ifdef MPF_VEC_INLINES_C #define MPF_VEC_INLINE FLINT_DLL #else #define MPF_VEC_INLINE static __inline__ #endif typedef __mpf_struct mpf; #ifdef __cplusplus extern "C" { #endif /* Memory management *******************************************************/ FLINT_DLL mpf * _mpf_vec_init(slong len, flint_bitcnt_t prec); FLINT_DLL void _mpf_vec_clear(mpf * vec, slong len); /* Randomisation ***********************************************************/ FLINT_DLL void _mpf_vec_randtest(mpf * f, flint_rand_t state, slong len, flint_bitcnt_t bits); /* Assignment and basic manipulation ***************************************/ FLINT_DLL void _mpf_vec_zero(mpf * vec, slong len); FLINT_DLL void _mpf_vec_set(mpf * vec1, const mpf * vec2, slong len2); /* Comparison **************************************************************/ FLINT_DLL int _mpf_vec_equal(const mpf * vec1, const mpf * vec2, slong len); FLINT_DLL int _mpf_vec_approx_equal(const mpf * vec1, const mpf * vec2, slong len, flint_bitcnt_t bits); FLINT_DLL int _mpf_vec_is_zero(const mpf * vec, slong len); /* Addition ****************************************************************/ FLINT_DLL void _mpf_vec_add(mpf * res, const mpf * vec1, const mpf * vec2, slong len2); FLINT_DLL void _mpf_vec_sub(mpf * res, const mpf * vec1, const mpf * vec2, slong len2); /* Scalar multiplication **************************************/ FLINT_DLL void _mpf_vec_scalar_mul_2exp(mpf * res, const mpf * vec, slong len, flint_bitcnt_t exp); FLINT_DLL void _mpf_vec_scalar_mul_mpf(mpf * res, const mpf * vec, slong len, mpf_t c); /* Dot product and norm **************************************/ FLINT_DLL void _mpf_vec_dot(mpf_t res, const mpf * vec1, const mpf * vec2, slong len2); FLINT_DLL void _mpf_vec_norm(mpf_t res, const mpf * vec, slong len); FLINT_DLL int _mpf_vec_dot2(mpf_t res, const mpf * vec1, const mpf * vec2, slong len2, flint_bitcnt_t prec); FLINT_DLL void _mpf_vec_norm2(mpf_t res, const mpf * vec, slong len, flint_bitcnt_t prec); #ifdef __cplusplus } #endif #endif #ifdef __cplusplus extern "C" { #endif #define FMPZ_VEC_NORM(vec, i) \ do { \ while ((i) && vec[(i) - 1] == WORD(0)) \ (i)--; \ } while (0) #define FMPZ_VEC_SWAP(vec1, len1, vec2, len2) \ do { \ fmpz *__t; \ slong __tn; \ __t = (vec1); \ (vec1) = (vec2); \ (vec2) = __t; \ __tn = (len1); \ (len1) = (len2); \ (len2) = __tn; \ } while (0); /* makes assignment to vec */ #define FMPZ_VEC_TMP_INIT(vec, len) \ do { \ fmpz * __vres; \ slong __vi; \ vec = __vres = TMP_ARRAY_ALLOC(len, fmpz); \ for (__vi = (len); __vi > 0; __vi--) \ fmpz_init(__vres + __vi - 1); \ } while (0) #define FMPZ_VEC_TMP_CLEAR(vec, len) \ do { \ fmpz * __vres = (vec); \ slong __vi; \ for (__vi = (len); __vi > 0; __vi--) \ fmpz_clear(__vres + __vi - 1); \ } while (0) /* Memory management *******************************************************/ FMPZ_VEC_INLINE fmpz * _fmpz_vec_init(slong len) { return (fmpz *) flint_calloc(len, sizeof(fmpz)); } FLINT_DLL void _fmpz_vec_clear(fmpz * vec, slong len); /* Randomisation ***********************************************************/ FLINT_DLL void _fmpz_vec_randtest(fmpz * f, flint_rand_t state, slong len, flint_bitcnt_t bits); FLINT_DLL void _fmpz_vec_randtest_unsigned(fmpz * f, flint_rand_t state, slong len, flint_bitcnt_t bits); /* Norms *******************************************************************/ FLINT_DLL slong _fmpz_vec_max_bits(const fmpz * vec, slong len); FLINT_DLL slong _fmpz_vec_max_bits_ref(const fmpz * vec, slong len); FLINT_DLL void _fmpz_vec_sum_max_bits(slong * sumabs, slong * maxabs, const fmpz * coeffs, slong length); FLINT_DLL mp_size_t _fmpz_vec_max_limbs(const fmpz * vec, slong len); FLINT_DLL void _fmpz_vec_height(fmpz_t height, const fmpz * vec, slong len); FLINT_DLL slong _fmpz_vec_height_index(const fmpz * vec, slong len); /* Input and output ********************************************************/ FLINT_DLL int _fmpz_vec_fprint(FILE * file, const fmpz * vec, slong len); FMPZ_VEC_INLINE int _fmpz_vec_print(const fmpz * vec, slong len) { return _fmpz_vec_fprint(stdout, vec, len); } FLINT_DLL int _fmpz_vec_fread(FILE * file, fmpz ** vec, slong * len); FMPZ_VEC_INLINE int _fmpz_vec_read(fmpz ** vec, slong * len) { return _fmpz_vec_fread(stdin, vec, len); } /* Conversions *************************************************************/ FLINT_DLL void _fmpz_vec_set_nmod_vec(fmpz * res, mp_srcptr poly, slong len, nmod_t mod); FLINT_DLL void _fmpz_vec_get_nmod_vec(mp_ptr res, const fmpz * poly, slong len, nmod_t mod); FLINT_DLL void _fmpz_vec_get_fft(mp_limb_t ** coeffs_f, const fmpz * coeffs_m, slong l, slong length); FLINT_DLL void _fmpz_vec_set_fft(fmpz * coeffs_m, slong length, const mp_ptr * coeffs_f, slong limbs, slong sign); FLINT_DLL slong _fmpz_vec_get_d_vec_2exp(double * appv, const fmpz * vec, slong len); FLINT_DLL void _fmpz_vec_get_mpf_vec(mpf * appv, const fmpz * vec, slong len); /* Assignment and basic manipulation ***************************************/ FLINT_DLL void _fmpz_vec_set(fmpz * vec1, const fmpz * vec2, slong len2); FLINT_DLL void _fmpz_vec_swap(fmpz * vec1, fmpz * vec2, slong len2); FLINT_DLL void _fmpz_vec_zero(fmpz * vec, slong len); FLINT_DLL void _fmpz_vec_neg(fmpz * vec1, const fmpz * vec2, slong len2); FLINT_DLL void _fmpz_vec_scalar_abs(fmpz * vec1, const fmpz * vec2, slong len2); /* Comparison **************************************************************/ FLINT_DLL int _fmpz_vec_equal(const fmpz * vec1, const fmpz * vec2, slong len); FLINT_DLL int _fmpz_vec_is_zero(const fmpz * vec, slong len); FLINT_DLL void _fmpz_vec_max(fmpz * vec1, const fmpz * vec2, const fmpz * vec3, slong len); FLINT_DLL void _fmpz_vec_max_inplace(fmpz * vec1, const fmpz * vec2, slong len); FLINT_DLL void _fmpz_vec_min(fmpz * vec1, const fmpz * vec2, const fmpz * vec3, slong len); FLINT_DLL void _fmpz_vec_min_inplace(fmpz * vec1, const fmpz * vec2, slong len); /* Sorting ******************************************************************/ FLINT_DLL void _fmpz_vec_sort(fmpz * vec, slong len); /* Addition ****************************************************************/ FLINT_DLL void _fmpz_vec_add(fmpz * res, const fmpz * vec1, const fmpz * vec2, slong len2); FLINT_DLL void _fmpz_vec_sub(fmpz * res, const fmpz * vec1, const fmpz * vec2, slong len2); /* Scalar multiplication and division **************************************/ FLINT_DLL void _fmpz_vec_scalar_mul_si(fmpz * vec1, const fmpz * vec2, slong len2, slong c); FLINT_DLL void _fmpz_vec_scalar_mul_ui(fmpz * vec1, const fmpz * vec2, slong len2, ulong c); FLINT_DLL void _fmpz_vec_scalar_mul_fmpz(fmpz * vec1, const fmpz * vec2, slong len2, const fmpz_t x); FLINT_DLL void _fmpz_vec_scalar_mul_2exp(fmpz * vec1, const fmpz * vec2, slong len2, ulong exp); FLINT_DLL void _fmpz_vec_scalar_divexact_fmpz(fmpz * vec1, const fmpz * vec2, slong len2, const fmpz_t x); FLINT_DLL void _fmpz_vec_scalar_divexact_si(fmpz * vec1, const fmpz * vec2, slong len2, slong c); FLINT_DLL void _fmpz_vec_scalar_divexact_ui(fmpz * vec1, const fmpz * vec2, slong len2, ulong c); FLINT_DLL void _fmpz_vec_scalar_fdiv_q_fmpz(fmpz * vec1, const fmpz * vec2, slong len2, const fmpz_t c); FLINT_DLL void _fmpz_vec_scalar_fdiv_q_si(fmpz * vec1, const fmpz * vec2, slong len2, slong c); FLINT_DLL void _fmpz_vec_scalar_fdiv_q_ui(fmpz * vec1, const fmpz * vec2, slong len2, ulong c); FLINT_DLL void _fmpz_vec_scalar_fdiv_q_2exp(fmpz * vec1, const fmpz * vec2, slong len2, ulong exp); FLINT_DLL void _fmpz_vec_scalar_fdiv_r_2exp(fmpz * vec1, const fmpz * vec2, slong len2, ulong exp); FLINT_DLL void _fmpz_vec_scalar_tdiv_q_fmpz(fmpz * vec1, const fmpz * vec2, slong len2, const fmpz_t c); FLINT_DLL void _fmpz_vec_scalar_tdiv_q_si(fmpz * vec1, const fmpz * vec2, slong len2, slong c); FLINT_DLL void _fmpz_vec_scalar_tdiv_q_ui(fmpz * vec1, const fmpz * vec2, slong len2, ulong c); FLINT_DLL void _fmpz_vec_scalar_tdiv_q_2exp(fmpz * vec1, const fmpz * vec2, slong len2, ulong exp); FLINT_DLL void _fmpz_vec_scalar_addmul_si(fmpz * vec1, const fmpz * vec2, slong len2, slong c); FLINT_DLL void _fmpz_vec_scalar_addmul_ui(fmpz * vec1, const fmpz * vec2, slong len2, ulong c); FLINT_DLL void _fmpz_vec_scalar_addmul_fmpz(fmpz * poly1, const fmpz * poly2, slong len2, const fmpz_t x); FLINT_DLL void _fmpz_vec_scalar_addmul_si_2exp(fmpz * vec1, const fmpz * vec2, slong len2, slong c, ulong exp); FLINT_DLL void _fmpz_vec_scalar_submul_si(fmpz * vec1, const fmpz * vec2, slong len2, slong c); FLINT_DLL void _fmpz_vec_scalar_submul_fmpz(fmpz * vec1, const fmpz * vec2, slong len2, const fmpz_t x); FLINT_DLL void _fmpz_vec_scalar_submul_si_2exp(fmpz * vec1, const fmpz * vec2, slong len2, slong c, ulong exp); /* Vector sum and product **************************************************/ FLINT_DLL void _fmpz_vec_sum(fmpz_t res, const fmpz * vec, slong len); FLINT_DLL void _fmpz_vec_prod(fmpz_t res, const fmpz * vec, slong len); /* Reduction mod p **********************************************************/ FLINT_DLL void _fmpz_vec_scalar_mod_fmpz(fmpz *res, const fmpz *vec, slong len, const fmpz_t p); FLINT_DLL void _fmpz_vec_scalar_smod_fmpz(fmpz *res, const fmpz *vec, slong len, const fmpz_t p); /* Gaussian content ********************************************************/ FLINT_DLL void _fmpz_vec_content(fmpz_t res, const fmpz * vec, slong len); FLINT_DLL void _fmpz_vec_content_chained(fmpz_t res, const fmpz * vec, slong len, const fmpz_t inp); FLINT_DLL void _fmpz_vec_lcm(fmpz_t res, const fmpz * vec, slong len); /* Dot product *************************************************************/ FLINT_DLL void _fmpz_vec_dot(fmpz_t res, const fmpz * vec1, const fmpz * vec2, slong len2); FLINT_DLL void _fmpz_vec_dot_ptr(fmpz_t c, const fmpz * vec1, fmpz ** const vec2, slong offset, slong len); #ifdef __cplusplus } #endif #endif // TODO codegen // TODO factor_pp1 multiple return values namespace flint { FLINT_DEFINE_THREEARY(factor_trial_range) FLINT_DEFINE_UNOP(expand) FLINT_DEFINE_UNOP(expand_iterative) FLINT_DEFINE_UNOP(expand_multiexp) namespace detail { template<class Delay> class fmpz_factorxx_delayed { private: fmpz_factor_t inner; void copy_init(const fmpz_factorxx_delayed& o) { _fmpz_factor_fit_length(inner, o.inner->num); _fmpz_factor_set_length(inner, o.inner->num); inner->sign = o.inner->sign; for(slong i = 0;i < o.inner->num;++i) { fmpz_set(inner->p + i, o.inner->p + i); inner->exp[i] = o.inner->exp[i]; } } public: fmpz_factorxx_delayed() {fmpz_factor_init(inner);} ~fmpz_factorxx_delayed() {fmpz_factor_clear(inner);} fmpz_factorxx_delayed(const fmpz_factorxx_delayed& o) { fmpz_factor_init(inner); copy_init(o); } fmpz_factorxx_delayed& operator=(const fmpz_factorxx_delayed& o) { copy_init(o); return *this; } bool operator==(const fmpz_factorxx_delayed& o) { if(o.sign() != sign() || o.size() != size()) return false; for(ulong i = 0;i < size();++i) if(p(i) != o.p(i) || exp(i) != o.exp(i)) return false; return true; } ulong size() const {return inner->num;} ulong exp(slong i) const {return inner->exp[i];} ulong& exp(slong i) {return inner->exp[i];} fmpzxx_srcref p(slong i) const {return fmpzxx_srcref::make(inner->p + i);} fmpzxx_ref p(slong i) {return fmpzxx_ref::make(inner->p + i);} int sign() const {return inner->sign;} int& sign() {return inner->sign;} fmpz_factor_t& _data() {return inner;} const fmpz_factor_t& _data() const {return inner;} void print() const {fmpz_factor_print(inner);} template<class Fmpz> typename mp::enable_if<traits::is_fmpzxx<Fmpz> >::type set_factor(const Fmpz& f) { fmpz_factor(_data(), f.evaluate()._fmpz()); } template<class T> typename mp::enable_if<traits::fits_into_slong<T> >::type set_factor(T t) { fmpz_factor_si(_data(), t); } template<class Fmpz> typename mp::enable_if<traits::is_fmpzxx<Fmpz>, bool>::type set_factor_trial_range(const Fmpz& f, ulong start, ulong nprimes) { return fmpz_factor_trial_range(_data(), f.evaluate()._fmpz(), start, nprimes); } template<class Fmpz> typename mp::enable_if<traits::is_fmpzxx<Fmpz>, bool>::type set_factor_pp1(const Fmpz& f, ulong B1, ulong B2_sqrt, ulong c) { return fmpz_factor_pp1(_data(), f.evaluate()._fmpz(), B1, B2_sqrt, c); } #define FLINTXX_DEFINE_MEMBER_UNOP_EXTRA(funcname, Class, rtype) \ FLINT_UNOP_BUILD_RETTYPE(funcname, rtype, Class) \ funcname() const {return flint::funcname(*this);} FLINTXX_DEFINE_MEMBER_UNOP_EXTRA(expand, fmpz_factorxx_delayed, fmpzxx) FLINTXX_DEFINE_MEMBER_UNOP_EXTRA(expand_iterative, fmpz_factorxx_delayed, fmpzxx) FLINTXX_DEFINE_MEMBER_UNOP_EXTRA(expand_multiexp, fmpz_factorxx_delayed, fmpzxx) }; } // detail typedef detail::fmpz_factorxx_delayed<void> fmpz_factorxx; template<class Fmpz> inline typename mp::enable_if<mp::or_< traits::is_fmpzxx<Fmpz>, traits::fits_into_slong<Fmpz> >, fmpz_factorxx>::type factor(const Fmpz& f) { fmpz_factorxx res; res.set_factor(f); return res; } namespace rules { namespace rdetail { typedef make_ltuple<mp::make_tuple<bool, fmpz_factorxx>::type>::type fmpz_factor_rt; template<class T> struct signed_or_fmpz : mp::or_<FMPZXX_COND_S<T>, traits::fits_into_slong<T> > { }; } // rdetail FLINT_DEFINE_THREEARY_EXPR_COND3(factor_trial_range_op, rdetail::fmpz_factor_rt, rdetail::signed_or_fmpz, traits::is_unsigned_integer, traits::is_unsigned_integer, to.template get<0>() = to.template get<1>().set_factor_trial_range( e1, e2, e3)) FLINT_DEFINE_UNARY_EXPR_(expand_op, fmpzxx, fmpz_factorxx, fmpz_factor_expand(to._fmpz(), from._data())) FLINT_DEFINE_UNARY_EXPR_(expand_iterative_op, fmpzxx, fmpz_factorxx, fmpz_factor_expand_iterative(to._fmpz(), from._data())) FLINT_DEFINE_UNARY_EXPR_(expand_multiexp_op, fmpzxx, fmpz_factorxx, fmpz_factor_expand_multiexp(to._fmpz(), from._data())) } // rules template<class Fmpz> inline typename mp::enable_if<traits::is_fmpzxx<Fmpz>, fmpz_factorxx>::type factor_pp1(const Fmpz& f, ulong B1, ulong B2_sqrt, ulong c) { fmpz_factorxx res; res.set_factor_pp1(f, B1, B2_sqrt, c); return res; } inline void print(const fmpz_factorxx& f) { f.print(); } } // flint #endif #endif using namespace flint; int main(int argc, char* argv[]) { if (argc != 2) { flint_printf("Syntax: crt <integer>\n"); return EXIT_FAILURE; } fmpzxx x(argv[1]); slong bit_bound = bits(x) + 2; fmpzxx y(0); fmpzxx prod(1); mp_limb_t prime = 0; for (unsigned i = 0; bits(prod) < bit_bound; i++) { prime = n_nextprime(prime, 0); ulong res = (x % prime).to<ulong>(); y = y.CRT(prod, res, prime, true); std::cout << "residue mod " << prime << " = " << res; std::cout << "; reconstruction = " << y << '\n'; prod *= prime; } return 0; } /* Copyright (C) 2016 William Hart This file is part of FLINT. FLINT is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See <https://www.gnu.org/licenses/>. */ #include <stdlib.h> #include <stdarg.h> #if FLINT_REENTRANT && !FLINT_USES_TLS #include <pthread.h> static pthread_once_t abort_func_init = PTHREAD_ONCE_INIT; pthread_mutex_t abort_func_lock; void __flint_set_abort_init() { pthread_mutex_init(&abort_func_lock, NULL); } #endif FLINT_NORETURN void (*abort_func)(void) = abort; void flint_set_abort(FLINT_NORETURN void (*func)(void)) { #if FLINT_REENTRANT && !FLINT_USES_TLS pthread_once(&abort_func_init, __flint_set_abort_init); pthread_mutex_lock(&abort_func_lock); #endif abort_func = func; #if FLINT_REENTRANT && !FLINT_USES_TLS pthread_mutex_unlock(&abort_func_lock); #endif } FLINT_NORETURN void flint_abort() { (*abort_func)(); } void flint_throw(flint_err_t exc, const char * msg, ...) { va_list ap; va_start(ap, msg); flint_printf("Flint exception ("); switch (exc) { case FLINT_ERROR: flint_printf("General error"); break; case FLINT_IMPINV: flint_printf("Impossible inverse"); break; case FLINT_DOMERR: flint_printf("Domain error"); break; case FLINT_DIVZERO: flint_printf("Divide by zero"); break; case FLINT_INEXACT: flint_printf("Inexact"); break; default: flint_printf("Unknown exception"); } printf("):\n "); flint_vprintf(msg, ap); va_end(ap); flint_abort(); }
Become a Patron
Sponsor on GitHub
Donate via PayPal
Compiler Explorer Shop
Source on GitHub
Mailing list
Installed libraries
Wiki
Report an issue
How it works
Contact the author
CE on Mastodon
CE on Bluesky
Statistics
Changelog
Version tree