100000000000032 100000000000032
user output:977232033
75801726076516 75801726076516
-
304250263527210 304250263527210
-
100000000000032 100000000000032
user output:977232033
75801726076516 75801726076516
-
304250263527210 304250263527210
-
#include <cassert>
#include <cstdio>
#include <fstream>
#include <string>
int main(int argc, char** argv) {
using namespace std;
assert(argc == 3);
ifstream in1(argv[1]);
ifstream in2(argv[2]);
string token1, token2;
int cnt1 = 0, cnt2 = 0;
while(true)
{
int tmp = cnt1;
cnt1 += bool(in1 >> token1);
cnt2 += bool(in2 >> token2);
if(cnt1 != cnt2 || tmp == cnt1)
break;
if(token1 != token2)
{
printf("wrong answer\nWrong answer on token %d, %s read %s, %s read %s.\n",
cnt1, argv[1], token1.c_str(), argv[2], token2.c_str());
return 17;
}
}
if(cnt1 < cnt2)
{
printf("wrong answer\nFile %s too short.\n", argv[1]);
return 18;
}
if(cnt2 < cnt1)
{
printf("wrong answer\nFile %s too short.\n", argv[2]);
return 19;
}
printf("ok %d tokens.\n", cnt1);
return 0;
}
#include <cassert>
#include <cstdio>
#include <fstream>
#include <string>
int main(int argc, char** argv) {
using namespace std;
assert(argc == 3);
ifstream in1(argv[1]);
ifstream in2(argv[2]);
string token1, token2;
int cnt1 = 0, cnt2 = 0;
while(true)
{
int tmp = cnt1;
cnt1 += bool(getline(in1, token1));
cnt2 += bool(getline(in2, token2));
if(cnt1 != cnt2 || tmp == cnt1)
break;
while(!token1.empty() && token1.back() == ' ')
token1.pop_back();
while(!token2.empty() && token2.back() == ' ')
token2.pop_back();
if(token1 != token2)
{
printf("wrong answer\nWrong answer on token %d, %s read %s, %s read %s.\n",
cnt1, argv[1], token1.c_str(), argv[2], token2.c_str());
return 17;
}
}
if(cnt1 < cnt2)
{
printf("wrong answer\nFile %s too short.\n", argv[1]);
return 18;
}
if(cnt2 < cnt1)
{
printf("wrong answer\nFile %s too short.\n", argv[2]);
return 19;
}
printf("ok %d tokens.\n", cnt1);
return 0;
}
#include "testlib.h"
#include <string>
#include <vector>
#include <sstream>
using namespace std;
bool compareWords(const string& a, const string& b) {
vector<string> va, vb;
stringstream sa;
sa << a;
string cur;
while (sa >> cur)
va.push_back(cur);
stringstream sb;
sb << b;
while (sb >> cur)
vb.push_back(cur);
return (va == vb);
}
int main(int argc, char *argv[]) {
setName("逐行比较 tokens");
registerTestlibCmd(argc, argv);
string strAnswer;
int n = 0;
while (!ans.eof()) {
std::string j = ans.readString();
if (j.empty() && ans.eof())
break;
string p = ouf.readString();
strAnswer = p;
n++;
if (!compareWords(j, p))
quitf(_wa, "第 %d 行不同 - 答案是 '%s',但是读取到 '%s'.", n,
compress(j).c_str(), compress(p).c_str());
}
if (n == 1)
quitf(_ok, "一行 '%s'.", compress(strAnswer).c_str());
quitf(_ok, "共 %d 行.", n);
}
#include <cassert>
#include <cmath>
#include <cstdio>
#include <fstream>
constexpr long double Eps = 1e-2;
int main(int argc, char** argv) {
using namespace std;
assert(argc == 3);
ifstream in1(argv[1]);
ifstream in2(argv[2]);
long double token1, token2;
int cnt1 = 0, cnt2 = 0;
while(true)
{
int tmp = cnt1;
cnt1 += bool(in1 >> token1);
cnt2 += bool(in2 >> token2);
if(cnt1 != cnt2 || tmp == cnt1)
break;
if(abs(token1 - token2) > Eps)
{
printf("wrong answer\nWrong answer on token %d, %Lf %Lf.\n",
cnt1, token1, token2);
return 17;
}
}
if(cnt1 < cnt2)
{
printf("wrong answer\nFile %s too short.\n", argv[1]);
return 18;
}
if(cnt2 < cnt1)
{
printf("wrong answer\nFile %s too short.\n", argv[2]);
return 19;
}
printf("ok %d tokens.\n", cnt1);
return 0;
}
可执行文件名称 输出文件名1 输出文件名2
#include <cassert>
#include <cstdio>
#include <ctime>
#include <fstream>
#include <string>
#ifdef _WIN32
#define COPY_COMMAND "copy"
#define REMOVE_COMMAND "del"
#define RUN_PREFIX ""
#else
#define COPY_COMMAND "cp"
#define REMOVE_COMMAND "rm"
#define RUN_PREFIX "./"
#endif
// 标准输入输出控制标志,文件输入输出请注释掉
#define STDIO
// 输入后缀
#define INF_SUF "in"
// 输出后缀
#define OUF_SUF "out"
// 答案后缀
#define ANS_SUF "ans"
// 从第几个大样例开始测试
#define TEST_START 1
// 默认你可执行文件名等于题目名称
// argv[1] 是可执行文件名,大样例没有前缀,argv[2]是大样例数目
// argv[1] 是可执行文件名,大样例前缀是 argv[3],argv[2]是大样例数目
// 用法两种
// 1. (./)本程序名 题目名称 要测试的大样例数量
// 2. (./)本程序名 题目名称 要测试的大样例数量 大样例前缀
int builtin_checker(std::string ouf, std::string ans);
int main(int argc, char** argv) {
using namespace std;
string title = argv[1], pre = "";
int cnt = stoi(argv[2]);
if(argc == 4)
pre = argv[3];
for(int i = TEST_START; i < TEST_START + cnt; i++)
{
system((COPY_COMMAND " " + pre + to_string(i) + "." INF_SUF " " + title + "." INF_SUF).c_str());
auto start = clock();
#ifdef STDIO
system((RUN_PREFIX + title + " < " + title + "." INF_SUF " >" + title + "." OUF_SUF).c_str());
#else
system((RUN_PREFIX + title).c_str());
#endif
double time = double(clock() - start) / CLOCKS_PER_SEC;
printf("%f s ", time);
if(builtin_checker(title + "." OUF_SUF, pre + to_string(i) + "." ANS_SUF))
return 16;
system((REMOVE_COMMAND " " + title + "." INF_SUF).c_str());
}
return 0;
}
int builtin_checker(std::string ouf, std::string ans) {
using namespace std;
ifstream in1(ouf);
ifstream in2(ans);
string token1, token2;
int cnt1 = 0, cnt2 = 0;
while(true)
{
int tmp = cnt1;
cnt1 += bool(getline(in1, token1));
cnt2 += bool(getline(in2, token2));
if(cnt1 != cnt2 || tmp == cnt1)
break;
while(!token1.empty() && token1.back() == ' ')
token1.pop_back();
while(!token2.empty() && token2.back() == ' ')
token2.pop_back();
if(token1 != token2)
{
printf("wrong answer\nWrong answer on token %d, %s read %s, %s expected %s.\n",
cnt1, ouf.c_str(), token1.c_str(), ans.c_str(), token2.c_str());
return 17;
}
}
if(cnt1 < cnt2)
{
printf("wrong answer\nFile %s too short.\n", ouf.c_str());
return 18;
}
if(cnt2 < cnt1)
{
printf("wrong answer\nFile %s too long.\n", ouf.c_str());
return 19;
}
printf("ok %d tokens.\n", cnt1);
return 0;
}
#include <cassert>
#include <chrono>
#include <cstdio>
#include <string>
// 大样例前缀(去掉题目名称)
#define SAMPLE_PREFIX ""
// 工作目录
#define WORK_DIR "cmake-build-debug"
// 运行命令
#define RUN_COMMAND "cd " WORK_DIR "&& ./OI_project_main"
// checker
#define CHECKER "./chk"
// 输入、输出、答案后缀
#define INPUT_SUFFIX ".in"
#define OUTPUT_SUFFIX ".out"
#define ANSWER_SUFFIX ".ans"
// 标准输入输出请启用这个
#define STDIO
// ./run_checks 数据点个数 数据点目录(题目名称)
void exit_fail(int ret) {
if (ret)
exit(ret);
}
int main(int argc, char** argv) {
using namespace std;
assert(argc == 3);
int cases = stoi(argv[1]);
string probtitle = argv[2];
printf("%s [%d cases]\n", probtitle.c_str(), cases);
for (int i = 1; i <= cases; i++)
{
printf("\nRunning test %d\n", i);
string ex_prefix = probtitle + "/" SAMPLE_PREFIX + probtitle + to_string(i);
system(("cp " + ex_prefix + INPUT_SUFFIX " " WORK_DIR "/" + probtitle + INPUT_SUFFIX).c_str());
auto start = chrono::high_resolution_clock::now();
#ifdef STDIO
exit_fail(system(
(RUN_COMMAND " < " + probtitle + INPUT_SUFFIX + " > " + probtitle + OUTPUT_SUFFIX).c_str()));
#else
exit_fail(system(RUN_COMMAND));
#endif
auto now = chrono::duration_cast<chrono::milliseconds>(chrono::high_resolution_clock::now() - start);
printf(" %.3fs ", now.count() / 1e3);
exit_fail(system((CHECKER " " WORK_DIR "/" + probtitle + OUTPUT_SUFFIX + " " + ex_prefix + ANSWER_SUFFIX).c_str()));
system(("rm " WORK_DIR "/" + probtitle + ".in").c_str());
system(("rm " WORK_DIR "/" + probtitle + ".out").c_str());
}
return 0;
}
#include <cassert>
#include <chrono>
#include <cstdio>
#include <string>
// 大样例前缀(去掉题目名称)
#define SAMPLE_PREFIX ""
// 工作目录
#define WORK_DIR "cmake-build-debug"
// 运行命令
#define RUN_COMMAND "cd " WORK_DIR "&& ./OI_project_main"
// checker
#define CHECKER "./chk"
// 输入、输出、答案后缀
#define INPUT_SUFFIX ".in"
#define OUTPUT_SUFFIX ".out"
#define ANSWER_SUFFIX ".ans"
// 标准输入输出请启用这个
#define STDIO
// ./run_checks 数据点个数 数据点目录(题目名称)
void exit_fail(int ret) {
if (ret)
exit(ret);
}
int main(int argc, char** argv) {
using namespace std;
assert(argc == 3);
int cases = stoi(argv[1]);
string probtitle = argv[2];
printf("%s [%d cases]\n", probtitle.c_str(), cases);
for (int i = 1; i <= cases; i++)
{
printf("\nRunning test %d\n", i);
string ex_prefix = probtitle + "/" SAMPLE_PREFIX + probtitle + to_string(i);
system(("cp " + ex_prefix + INPUT_SUFFIX " " WORK_DIR "/" + probtitle + INPUT_SUFFIX).c_str());
auto start = chrono::high_resolution_clock::now();
#ifdef STDIO
exit_fail(system(
(RUN_COMMAND " < " + probtitle + INPUT_SUFFIX + " > " + probtitle + OUTPUT_SUFFIX).c_str()));
#else
exit_fail(system(RUN_COMMAND));
#endif
auto now = chrono::duration_cast<chrono::milliseconds>(chrono::high_resolution_clock::now() - start);
printf(" %.3fs ", now.count() / 1e3);
exit_fail(system((CHECKER " " + ex_prefix + INPUT_SUFFIX " " WORK_DIR "/" + probtitle + OUTPUT_SUFFIX + " " + ex_prefix + ANSWER_SUFFIX).c_str()));
system(("rm " WORK_DIR "/" + probtitle + ".in").c_str());
system(("rm " WORK_DIR "/" + probtitle + ".out").c_str());
}
return 0;
}
#include <cassert>
#include <chrono>
#include <cstdio>
#include <cstdlib>
#include <string>
#include <unistd.h>
#include <vector>
#include <sys/resource.h>
#include <sys/wait.h>
// ====================== 配置 ======================
#define SAMPLE_PREFIX ""
#define WORK_DIR "cmake-build-debug"
#define RUN_BINARY "./OI_project_main"
#define CHECKER "./chk"
#define INPUT_SUFFIX ".in"
#define OUTPUT_SUFFIX ".out"
#define ANSWER_SUFFIX ".ans"
// 如果使用 STDIN/STDOUT 则启用
#define STDIO
// =================================================
void exit_fail(int ret) {
if (ret) exit(ret);
}
/**
* 运行程序并测量时间与内存占用
* - input_path: 输入文件(用于 STDIO 模式)
* - output_path: 输出文件(用于 STDIO 模式)
* - bin_args: 可执行文件相对 WORK_DIR 的运行参数(用于文件 I/O 模式)
*
* 返回 (wall_time_ms, max_memory_kb)
*/
std::pair<long long, long long> run_and_measure(
const std::string& input_path,
const std::string& output_path,
const std::vector<std::string>& bin_args
) {
using namespace std;
auto start = chrono::steady_clock::now();
pid_t pid = fork();
if (pid < 0)
{
perror("fork");
exit(1);
}
if (pid == 0)
{
// 子进程
if (chdir(WORK_DIR) != 0)
{
perror("chdir");
exit(1);
}
#ifdef STDIO
// STDIN/STDOUT 重定向
if (!input_path.empty())
{
freopen(input_path.c_str(), "r", stdin);
}
if (!output_path.empty())
{
freopen(output_path.c_str(), "w", stdout);
}
// 构造 exec 参数
std::vector<char*> args;
args.push_back(const_cast<char*>(RUN_BINARY));
args.push_back(nullptr);
execvp(args[0], args.data());
#else
// 文件 I/O 模式:直接传递参数,不做重定向
// 构造 exec 参数
std::vector<char*> args;
args.push_back(const_cast<char*>(RUN_BINARY));
for (auto &s : bin_args)
args.push_back(const_cast<char*>(s.c_str()));
args.push_back(nullptr);
execvp(args[0], args.data());
#endif
perror("execvp");
exit(1);
}
// 父进程:等待子进程并收集 rusage
int status;
struct rusage usage{};
wait4(pid, &status, 0, &usage);
auto end = chrono::steady_clock::now();
long long ms = chrono::duration_cast<chrono::milliseconds>(end - start).count();
long long mem = usage.ru_maxrss;
return {ms, mem};
}
int main(int argc, char** argv) {
using namespace std;
assert(argc == 3);
int cases = stoi(argv[1]);
string probtitle = argv[2];
printf("%s [%d cases]\n", probtitle.c_str(), cases);
for (int i = 1; i <= cases; i++)
{
printf("\nRunning test %d\n", i);
string prefix = probtitle + "/" SAMPLE_PREFIX + probtitle + to_string(i);
string in_path = prefix + INPUT_SUFFIX;
string ans_path = prefix + ANSWER_SUFFIX;
string local_in = WORK_DIR "/" + probtitle + INPUT_SUFFIX;
string local_out = WORK_DIR "/" + probtitle + OUTPUT_SUFFIX;
// 复制输入文件到工作目录/题目.in
system(("cp " + in_path + " " + local_in).c_str());
#ifdef STDIO
// 测试运行(STDIO 模式)
auto [time_ms, mem] = run_and_measure(
probtitle + INPUT_SUFFIX,
probtitle + OUTPUT_SUFFIX,
{}
);
#else
std::vector<std::string> args{};
auto [time_ms, mem] = run_and_measure(
"", "", // 不用 STDIO
args
);
#endif
printf("%.3fs, %.3fMB\n", time_ms / 1e3, mem / 1048576.0);
// Checker
exit_fail(system(
(CHECKER " " + local_in + " " + local_out + " " + ans_path).c_str()
));
system(("rm " + local_in).c_str());
system(("rm " + local_out).c_str());
}
return 0;
}
使用方法:洛谷题单左下角多选,右下角导出 $\texttt{T}$纯题号,输入进去会输出 vjudge 题单格式。
#include <iostream>
#include <algorithm>
#include <string>
#include <vector>
int main() {
using namespace std;
string src;
cin >> src;
src.push_back(',');
string tmp;
vector<string> set;
for(auto ch : src)
if(ch == ',')
{
set.push_back(tmp);
tmp.clear();
}
else
tmp.push_back(ch);
sort(set.begin(), set.end());
for(const auto& i : set)
{
cout << "[problem:";
if(i.size() > 2 && i.substr(0, 2) == "AT")
cout << "AtCoder-" << i.substr(3);
else if(i.size() > 1 && i.substr(0, 2) == "CF")
cout << "CodeForces-" << i.substr(2);
else if(i.size() > 2 && i.substr(0, 3) == "UVA")
cout << "UVA-" << i.substr(3);
else
cout << "洛谷-" << i;
cout << "]\n";
}
return 0;
}
/* mini-gmp, a minimalistic implementation of a GNU GMP subset.
Contributed to the GNU project by Niels M枚ller
Additional functionalities and improvements by Marco Bodrato.
Copyright 1991-1997, 1999-2022 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 either:
* the GNU Lesser General Public License as published by the Free
Software Foundation; either version 3 of the License, or (at your
option) any later version.
or
* the GNU General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any
later version.
or both in parallel, as here.
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 General Public License
for more details.
You should have received copies of the GNU General Public License and the
GNU Lesser General Public License along with the GNU MP Library. If not,
see https://www.gnu.org/licenses/. */
/* NOTE: All functions in this file which are not declared in
mini-gmp.h are internal, and are not intended to be compatible
with GMP or with future versions of mini-gmp. */
/* Much of the material copied from GMP files, including: gmp-impl.h,
longlong.h, mpn/generic/add_n.c, mpn/generic/addmul_1.c,
mpn/generic/lshift.c, mpn/generic/mul_1.c,
mpn/generic/mul_basecase.c, mpn/generic/rshift.c,
mpn/generic/sbpi1_div_qr.c, mpn/generic/sub_n.c,
mpn/generic/submul_1.c. */
#include <assert.h>
#include <ctype.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* mini-gmp, a minimalistic implementation of a GNU GMP subset.
Copyright 2011-2015, 2017, 2019-2021 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 either:
* the GNU Lesser General Public License as published by the Free
Software Foundation; either version 3 of the License, or (at your
option) any later version.
or
* the GNU General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any
later version.
or both in parallel, as here.
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 General Public License
for more details.
You should have received copies of the GNU General Public License and the
GNU Lesser General Public License along with the GNU MP Library. If not,
see https://www.gnu.org/licenses/. */
/* About mini-gmp: This is a minimal implementation of a subset of the
GMP interface. It is intended for inclusion into applications which
have modest bignums needs, as a fallback when the real GMP library
is not installed.
This file defines the public interface. */
#ifndef __MINI_GMP_H__
#define __MINI_GMP_H__
/* For size_t */
#include <stddef.h>
#if defined (__cplusplus)
extern "C" {
#endif
void mp_set_memory_functions (void *(*) (size_t),
void *(*) (void *, size_t, size_t),
void (*) (void *, size_t));
void mp_get_memory_functions (void *(**) (size_t),
void *(**) (void *, size_t, size_t),
void (**) (void *, size_t));
#ifndef MINI_GMP_LIMB_TYPE
#define MINI_GMP_LIMB_TYPE long
#endif
typedef unsigned MINI_GMP_LIMB_TYPE mp_limb_t;
typedef long mp_size_t;
typedef unsigned long mp_bitcnt_t;
typedef mp_limb_t *mp_ptr;
typedef const mp_limb_t *mp_srcptr;
typedef struct
{
int _mp_alloc; /* Number of *limbs* allocated and pointed
to by the _mp_d field. */
int _mp_size; /* abs(_mp_size) is the number of limbs the
last field points to. If _mp_size is
negative this is a negative number. */
mp_limb_t *_mp_d; /* Pointer to the limbs. */
} __mpz_struct;
typedef __mpz_struct mpz_t[1];
typedef __mpz_struct *mpz_ptr;
typedef const __mpz_struct *mpz_srcptr;
extern const int mp_bits_per_limb;
void mpn_copyi (mp_ptr, mp_srcptr, mp_size_t);
void mpn_copyd (mp_ptr, mp_srcptr, mp_size_t);
void mpn_zero (mp_ptr, mp_size_t);
int mpn_cmp (mp_srcptr, mp_srcptr, mp_size_t);
int mpn_zero_p (mp_srcptr, mp_size_t);
mp_limb_t mpn_add_1 (mp_ptr, mp_srcptr, mp_size_t, mp_limb_t);
mp_limb_t mpn_add_n (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t);
mp_limb_t mpn_add (mp_ptr, mp_srcptr, mp_size_t, mp_srcptr, mp_size_t);
mp_limb_t mpn_sub_1 (mp_ptr, mp_srcptr, mp_size_t, mp_limb_t);
mp_limb_t mpn_sub_n (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t);
mp_limb_t mpn_sub (mp_ptr, mp_srcptr, mp_size_t, mp_srcptr, mp_size_t);
mp_limb_t mpn_mul_1 (mp_ptr, mp_srcptr, mp_size_t, mp_limb_t);
mp_limb_t mpn_addmul_1 (mp_ptr, mp_srcptr, mp_size_t, mp_limb_t);
mp_limb_t mpn_submul_1 (mp_ptr, mp_srcptr, mp_size_t, mp_limb_t);
mp_limb_t mpn_mul (mp_ptr, mp_srcptr, mp_size_t, mp_srcptr, mp_size_t);
void mpn_mul_n (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t);
void mpn_sqr (mp_ptr, mp_srcptr, mp_size_t);
int mpn_perfect_square_p (mp_srcptr, mp_size_t);
mp_size_t mpn_sqrtrem (mp_ptr, mp_ptr, mp_srcptr, mp_size_t);
mp_limb_t mpn_lshift (mp_ptr, mp_srcptr, mp_size_t, unsigned int);
mp_limb_t mpn_rshift (mp_ptr, mp_srcptr, mp_size_t, unsigned int);
mp_bitcnt_t mpn_scan0 (mp_srcptr, mp_bitcnt_t);
mp_bitcnt_t mpn_scan1 (mp_srcptr, mp_bitcnt_t);
void mpn_com (mp_ptr, mp_srcptr, mp_size_t);
mp_limb_t mpn_neg (mp_ptr, mp_srcptr, mp_size_t);
mp_bitcnt_t mpn_popcount (mp_srcptr, mp_size_t);
mp_limb_t mpn_invert_3by2 (mp_limb_t, mp_limb_t);
#define mpn_invert_limb(x) mpn_invert_3by2 ((x), 0)
size_t mpn_get_str (unsigned char *, int, mp_ptr, mp_size_t);
mp_size_t mpn_set_str (mp_ptr, const unsigned char *, size_t, int);
void mpz_init (mpz_t);
void mpz_init2 (mpz_t, mp_bitcnt_t);
void mpz_clear (mpz_t);
#define mpz_odd_p(z) (((z)->_mp_size != 0) & (int) (z)->_mp_d[0])
#define mpz_even_p(z) (! mpz_odd_p (z))
int mpz_sgn (const mpz_t);
int mpz_cmp_si (const mpz_t, long);
int mpz_cmp_ui (const mpz_t, unsigned long);
int mpz_cmp (const mpz_t, const mpz_t);
int mpz_cmpabs_ui (const mpz_t, unsigned long);
int mpz_cmpabs (const mpz_t, const mpz_t);
int mpz_cmp_d (const mpz_t, double);
int mpz_cmpabs_d (const mpz_t, double);
void mpz_abs (mpz_t, const mpz_t);
void mpz_neg (mpz_t, const mpz_t);
void mpz_swap (mpz_t, mpz_t);
void mpz_add_ui (mpz_t, const mpz_t, unsigned long);
void mpz_add (mpz_t, const mpz_t, const mpz_t);
void mpz_sub_ui (mpz_t, const mpz_t, unsigned long);
void mpz_ui_sub (mpz_t, unsigned long, const mpz_t);
void mpz_sub (mpz_t, const mpz_t, const mpz_t);
void mpz_mul_si (mpz_t, const mpz_t, long int);
void mpz_mul_ui (mpz_t, const mpz_t, unsigned long int);
void mpz_mul (mpz_t, const mpz_t, const mpz_t);
void mpz_mul_2exp (mpz_t, const mpz_t, mp_bitcnt_t);
void mpz_addmul_ui (mpz_t, const mpz_t, unsigned long int);
void mpz_addmul (mpz_t, const mpz_t, const mpz_t);
void mpz_submul_ui (mpz_t, const mpz_t, unsigned long int);
void mpz_submul (mpz_t, const mpz_t, const mpz_t);
void mpz_cdiv_qr (mpz_t, mpz_t, const mpz_t, const mpz_t);
void mpz_fdiv_qr (mpz_t, mpz_t, const mpz_t, const mpz_t);
void mpz_tdiv_qr (mpz_t, mpz_t, const mpz_t, const mpz_t);
void mpz_cdiv_q (mpz_t, const mpz_t, const mpz_t);
void mpz_fdiv_q (mpz_t, const mpz_t, const mpz_t);
void mpz_tdiv_q (mpz_t, const mpz_t, const mpz_t);
void mpz_cdiv_r (mpz_t, const mpz_t, const mpz_t);
void mpz_fdiv_r (mpz_t, const mpz_t, const mpz_t);
void mpz_tdiv_r (mpz_t, const mpz_t, const mpz_t);
void mpz_cdiv_q_2exp (mpz_t, const mpz_t, mp_bitcnt_t);
void mpz_fdiv_q_2exp (mpz_t, const mpz_t, mp_bitcnt_t);
void mpz_tdiv_q_2exp (mpz_t, const mpz_t, mp_bitcnt_t);
void mpz_cdiv_r_2exp (mpz_t, const mpz_t, mp_bitcnt_t);
void mpz_fdiv_r_2exp (mpz_t, const mpz_t, mp_bitcnt_t);
void mpz_tdiv_r_2exp (mpz_t, const mpz_t, mp_bitcnt_t);
void mpz_mod (mpz_t, const mpz_t, const mpz_t);
void mpz_divexact (mpz_t, const mpz_t, const mpz_t);
int mpz_divisible_p (const mpz_t, const mpz_t);
int mpz_congruent_p (const mpz_t, const mpz_t, const mpz_t);
unsigned long mpz_cdiv_qr_ui (mpz_t, mpz_t, const mpz_t, unsigned long);
unsigned long mpz_fdiv_qr_ui (mpz_t, mpz_t, const mpz_t, unsigned long);
unsigned long mpz_tdiv_qr_ui (mpz_t, mpz_t, const mpz_t, unsigned long);
unsigned long mpz_cdiv_q_ui (mpz_t, const mpz_t, unsigned long);
unsigned long mpz_fdiv_q_ui (mpz_t, const mpz_t, unsigned long);
unsigned long mpz_tdiv_q_ui (mpz_t, const mpz_t, unsigned long);
unsigned long mpz_cdiv_r_ui (mpz_t, const mpz_t, unsigned long);
unsigned long mpz_fdiv_r_ui (mpz_t, const mpz_t, unsigned long);
unsigned long mpz_tdiv_r_ui (mpz_t, const mpz_t, unsigned long);
unsigned long mpz_cdiv_ui (const mpz_t, unsigned long);
unsigned long mpz_fdiv_ui (const mpz_t, unsigned long);
unsigned long mpz_tdiv_ui (const mpz_t, unsigned long);
unsigned long mpz_mod_ui (mpz_t, const mpz_t, unsigned long);
void mpz_divexact_ui (mpz_t, const mpz_t, unsigned long);
int mpz_divisible_ui_p (const mpz_t, unsigned long);
unsigned long mpz_gcd_ui (mpz_t, const mpz_t, unsigned long);
void mpz_gcd (mpz_t, const mpz_t, const mpz_t);
void mpz_gcdext (mpz_t, mpz_t, mpz_t, const mpz_t, const mpz_t);
void mpz_lcm_ui (mpz_t, const mpz_t, unsigned long);
void mpz_lcm (mpz_t, const mpz_t, const mpz_t);
int mpz_invert (mpz_t, const mpz_t, const mpz_t);
void mpz_sqrtrem (mpz_t, mpz_t, const mpz_t);
void mpz_sqrt (mpz_t, const mpz_t);
int mpz_perfect_square_p (const mpz_t);
void mpz_pow_ui (mpz_t, const mpz_t, unsigned long);
void mpz_ui_pow_ui (mpz_t, unsigned long, unsigned long);
void mpz_powm (mpz_t, const mpz_t, const mpz_t, const mpz_t);
void mpz_powm_ui (mpz_t, const mpz_t, unsigned long, const mpz_t);
void mpz_rootrem (mpz_t, mpz_t, const mpz_t, unsigned long);
int mpz_root (mpz_t, const mpz_t, unsigned long);
void mpz_fac_ui (mpz_t, unsigned long);
void mpz_2fac_ui (mpz_t, unsigned long);
void mpz_mfac_uiui (mpz_t, unsigned long, unsigned long);
void mpz_bin_uiui (mpz_t, unsigned long, unsigned long);
int mpz_probab_prime_p (const mpz_t, int);
int mpz_tstbit (const mpz_t, mp_bitcnt_t);
void mpz_setbit (mpz_t, mp_bitcnt_t);
void mpz_clrbit (mpz_t, mp_bitcnt_t);
void mpz_combit (mpz_t, mp_bitcnt_t);
void mpz_com (mpz_t, const mpz_t);
void mpz_and (mpz_t, const mpz_t, const mpz_t);
void mpz_ior (mpz_t, const mpz_t, const mpz_t);
void mpz_xor (mpz_t, const mpz_t, const mpz_t);
mp_bitcnt_t mpz_popcount (const mpz_t);
mp_bitcnt_t mpz_hamdist (const mpz_t, const mpz_t);
mp_bitcnt_t mpz_scan0 (const mpz_t, mp_bitcnt_t);
mp_bitcnt_t mpz_scan1 (const mpz_t, mp_bitcnt_t);
int mpz_fits_slong_p (const mpz_t);
int mpz_fits_ulong_p (const mpz_t);
int mpz_fits_sint_p (const mpz_t);
int mpz_fits_uint_p (const mpz_t);
int mpz_fits_sshort_p (const mpz_t);
int mpz_fits_ushort_p (const mpz_t);
long int mpz_get_si (const mpz_t);
unsigned long int mpz_get_ui (const mpz_t);
double mpz_get_d (const mpz_t);
size_t mpz_size (const mpz_t);
mp_limb_t mpz_getlimbn (const mpz_t, mp_size_t);
void mpz_realloc2 (mpz_t, mp_bitcnt_t);
mp_srcptr mpz_limbs_read (mpz_srcptr);
mp_ptr mpz_limbs_modify (mpz_t, mp_size_t);
mp_ptr mpz_limbs_write (mpz_t, mp_size_t);
void mpz_limbs_finish (mpz_t, mp_size_t);
mpz_srcptr mpz_roinit_n (mpz_t, mp_srcptr, mp_size_t);
#define MPZ_ROINIT_N(xp, xs) {{0, (xs),(xp) }}
void mpz_set_si (mpz_t, signed long int);
void mpz_set_ui (mpz_t, unsigned long int);
void mpz_set (mpz_t, const mpz_t);
void mpz_set_d (mpz_t, double);
void mpz_init_set_si (mpz_t, signed long int);
void mpz_init_set_ui (mpz_t, unsigned long int);
void mpz_init_set (mpz_t, const mpz_t);
void mpz_init_set_d (mpz_t, double);
size_t mpz_sizeinbase (const mpz_t, int);
char *mpz_get_str (char *, int, const mpz_t);
int mpz_set_str (mpz_t, const char *, int);
int mpz_init_set_str (mpz_t, const char *, int);
/* This long list taken from gmp.h. */
/* For reference, "defined(EOF)" cannot be used here. In g++ 2.95.4,
<iostream> defines EOF but not FILE. */
#if defined (FILE) \
|| defined (H_STDIO) \
|| defined (_H_STDIO) /* AIX */ \
|| defined (_STDIO_H) /* glibc, Sun, SCO */ \
|| defined (_STDIO_H_) /* BSD, OSF */ \
|| defined (__STDIO_H) /* Borland */ \
|| defined (__STDIO_H__) /* IRIX */ \
|| defined (_STDIO_INCLUDED) /* HPUX */ \
|| defined (__dj_include_stdio_h_) /* DJGPP */ \
|| defined (_FILE_DEFINED) /* Microsoft */ \
|| defined (__STDIO__) /* Apple MPW MrC */ \
|| defined (_MSL_STDIO_H) /* Metrowerks */ \
|| defined (_STDIO_H_INCLUDED) /* QNX4 */ \
|| defined (_ISO_STDIO_ISO_H) /* Sun C++ */ \
|| defined (__STDIO_LOADED) /* VMS */ \
|| defined (_STDIO) /* HPE NonStop */ \
|| defined (__DEFINED_FILE) /* musl */
size_t mpz_out_str (FILE *, int, const mpz_t);
#endif
void mpz_import (mpz_t, size_t, int, size_t, int, size_t, const void *);
void *mpz_export (void *, size_t *, int, size_t, int, size_t, const mpz_t);
#if defined (__cplusplus)
}
#endif
#endif /* __MINI_GMP_H__ */
#if !defined(MINI_GMP_DONT_USE_FLOAT_H)
#include <float.h>
#endif
/* Macros */
#define GMP_LIMB_BITS (sizeof(mp_limb_t) * CHAR_BIT)
#define GMP_LIMB_MAX ((mp_limb_t) ~ (mp_limb_t) 0)
#define GMP_LIMB_HIGHBIT ((mp_limb_t) 1 << (GMP_LIMB_BITS - 1))
#define GMP_HLIMB_BIT ((mp_limb_t) 1 << (GMP_LIMB_BITS / 2))
#define GMP_LLIMB_MASK (GMP_HLIMB_BIT - 1)
#define GMP_ULONG_BITS (sizeof(unsigned long) * CHAR_BIT)
#define GMP_ULONG_HIGHBIT ((unsigned long) 1 << (GMP_ULONG_BITS - 1))
#define GMP_ABS(x) ((x) >= 0 ? (x) : -(x))
#define GMP_NEG_CAST(T,x) (-((T)((x) + 1) - 1))
#define GMP_MIN(a, b) ((a) < (b) ? (a) : (b))
#define GMP_MAX(a, b) ((a) > (b) ? (a) : (b))
#define GMP_CMP(a,b) (((a) > (b)) - ((a) < (b)))
#if defined(DBL_MANT_DIG) && FLT_RADIX == 2
#define GMP_DBL_MANT_BITS DBL_MANT_DIG
#else
#define GMP_DBL_MANT_BITS (53)
#endif
/* Return non-zero if xp,xsize and yp,ysize overlap.
If xp+xsize<=yp there's no overlap, or if yp+ysize<=xp there's no
overlap. If both these are false, there's an overlap. */
#define GMP_MPN_OVERLAP_P(xp, xsize, yp, ysize) \
((xp) + (xsize) > (yp) && (yp) + (ysize) > (xp))
#define gmp_assert_nocarry(x) do { \
mp_limb_t __cy = (x); \
assert (__cy == 0); \
(void) (__cy); \
} while (0)
#define gmp_clz(count, x) do { \
mp_limb_t __clz_x = (x); \
unsigned __clz_c = 0; \
int LOCAL_SHIFT_BITS = 8; \
if (GMP_LIMB_BITS > LOCAL_SHIFT_BITS) \
for (; \
(__clz_x & ((mp_limb_t) 0xff << (GMP_LIMB_BITS - 8))) == 0; \
__clz_c += 8) \
{ __clz_x <<= LOCAL_SHIFT_BITS; } \
for (; (__clz_x & GMP_LIMB_HIGHBIT) == 0; __clz_c++) \
__clz_x <<= 1; \
(count) = __clz_c; \
} while (0)
#define gmp_ctz(count, x) do { \
mp_limb_t __ctz_x = (x); \
unsigned __ctz_c = 0; \
gmp_clz (__ctz_c, __ctz_x & - __ctz_x); \
(count) = GMP_LIMB_BITS - 1 - __ctz_c; \
} while (0)
#define gmp_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)
#define gmp_sub_ddmmss(sh, sl, ah, al, bh, bl) \
do { \
mp_limb_t __x; \
__x = (al) - (bl); \
(sh) = (ah) - (bh) - ((al) < (bl)); \
(sl) = __x; \
} while (0)
#define gmp_umul_ppmm(w1, w0, u, v) \
do { \
int LOCAL_GMP_LIMB_BITS = GMP_LIMB_BITS; \
if (sizeof(unsigned int) * CHAR_BIT >= 2 * GMP_LIMB_BITS) \
{ \
unsigned int __ww = (unsigned int) (u) * (v); \
w0 = (mp_limb_t) __ww; \
w1 = (mp_limb_t) (__ww >> LOCAL_GMP_LIMB_BITS); \
} \
else if (GMP_ULONG_BITS >= 2 * GMP_LIMB_BITS) \
{ \
unsigned long int __ww = (unsigned long int) (u) * (v); \
w0 = (mp_limb_t) __ww; \
w1 = (mp_limb_t) (__ww >> LOCAL_GMP_LIMB_BITS); \
} \
else { \
mp_limb_t __x0, __x1, __x2, __x3; \
unsigned __ul, __vl, __uh, __vh; \
mp_limb_t __u = (u), __v = (v); \
assert (sizeof (unsigned) * 2 >= sizeof (mp_limb_t)); \
\
__ul = __u & GMP_LLIMB_MASK; \
__uh = __u >> (GMP_LIMB_BITS / 2); \
__vl = __v & GMP_LLIMB_MASK; \
__vh = __v >> (GMP_LIMB_BITS / 2); \
\
__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 += __x0 >> (GMP_LIMB_BITS / 2);/* this can't give carry */ \
__x1 += __x2; /* but this indeed can */ \
if (__x1 < __x2) /* did we get it? */ \
__x3 += GMP_HLIMB_BIT; /* yes, add it in the proper pos. */ \
\
(w1) = __x3 + (__x1 >> (GMP_LIMB_BITS / 2)); \
(w0) = (__x1 << (GMP_LIMB_BITS / 2)) + (__x0 & GMP_LLIMB_MASK); \
} \
} while (0)
/* If mp_limb_t is of size smaller than int, plain u*v implies
automatic promotion to *signed* int, and then multiply may overflow
and cause undefined behavior. Explicitly cast to unsigned int for
that case. */
#define gmp_umullo_limb(u, v) \
((sizeof(mp_limb_t) >= sizeof(int)) ? (u)*(v) : (unsigned int)(u) * (v))
#define gmp_udiv_qrnnd_preinv(q, r, nh, nl, d, di) \
do { \
mp_limb_t _qh, _ql, _r, _mask; \
gmp_umul_ppmm (_qh, _ql, (nh), (di)); \
gmp_add_ssaaaa (_qh, _ql, _qh, _ql, (nh) + 1, (nl)); \
_r = (nl) - gmp_umullo_limb (_qh, (d)); \
_mask = -(mp_limb_t) (_r > _ql); /* both > and >= are OK */ \
_qh += _mask; \
_r += _mask & (d); \
if (_r >= (d)) \
{ \
_r -= (d); \
_qh++; \
} \
\
(r) = _r; \
(q) = _qh; \
} while (0)
#define gmp_udiv_qr_3by2(q, r1, r0, n2, n1, n0, d1, d0, dinv) \
do { \
mp_limb_t _q0, _t1, _t0, _mask; \
gmp_umul_ppmm ((q), _q0, (n2), (dinv)); \
gmp_add_ssaaaa ((q), _q0, (q), _q0, (n2), (n1)); \
\
/* Compute the two most significant limbs of n - q'd */ \
(r1) = (n1) - gmp_umullo_limb ((d1), (q)); \
gmp_sub_ddmmss ((r1), (r0), (r1), (n0), (d1), (d0)); \
gmp_umul_ppmm (_t1, _t0, (d0), (q)); \
gmp_sub_ddmmss ((r1), (r0), (r1), (r0), _t1, _t0); \
(q)++; \
\
/* Conditionally adjust q and the remainders */ \
_mask = - (mp_limb_t) ((r1) >= _q0); \
(q) += _mask; \
gmp_add_ssaaaa ((r1), (r0), (r1), (r0), _mask & (d1), _mask & (d0)); \
if ((r1) >= (d1)) \
{ \
if ((r1) > (d1) || (r0) >= (d0)) \
{ \
(q)++; \
gmp_sub_ddmmss ((r1), (r0), (r1), (r0), (d1), (d0)); \
} \
} \
} while (0)
/* Swap macros. */
#define MP_LIMB_T_SWAP(x, y) \
do { \
mp_limb_t __mp_limb_t_swap__tmp = (x); \
(x) = (y); \
(y) = __mp_limb_t_swap__tmp; \
} while (0)
#define MP_SIZE_T_SWAP(x, y) \
do { \
mp_size_t __mp_size_t_swap__tmp = (x); \
(x) = (y); \
(y) = __mp_size_t_swap__tmp; \
} while (0)
#define MP_BITCNT_T_SWAP(x,y) \
do { \
mp_bitcnt_t __mp_bitcnt_t_swap__tmp = (x); \
(x) = (y); \
(y) = __mp_bitcnt_t_swap__tmp; \
} while (0)
#define MP_PTR_SWAP(x, y) \
do { \
mp_ptr __mp_ptr_swap__tmp = (x); \
(x) = (y); \
(y) = __mp_ptr_swap__tmp; \
} while (0)
#define MP_SRCPTR_SWAP(x, y) \
do { \
mp_srcptr __mp_srcptr_swap__tmp = (x); \
(x) = (y); \
(y) = __mp_srcptr_swap__tmp; \
} while (0)
#define MPN_PTR_SWAP(xp,xs, yp,ys) \
do { \
MP_PTR_SWAP (xp, yp); \
MP_SIZE_T_SWAP (xs, ys); \
} while(0)
#define MPN_SRCPTR_SWAP(xp,xs, yp,ys) \
do { \
MP_SRCPTR_SWAP (xp, yp); \
MP_SIZE_T_SWAP (xs, ys); \
} while(0)
#define MPZ_PTR_SWAP(x, y) \
do { \
mpz_ptr __mpz_ptr_swap__tmp = (x); \
(x) = (y); \
(y) = __mpz_ptr_swap__tmp; \
} while (0)
#define MPZ_SRCPTR_SWAP(x, y) \
do { \
mpz_srcptr __mpz_srcptr_swap__tmp = (x); \
(x) = (y); \
(y) = __mpz_srcptr_swap__tmp; \
} while (0)
const int mp_bits_per_limb = GMP_LIMB_BITS;
/* Memory allocation and other helper functions. */
static void
gmp_die (const char *msg)
{
fprintf (stderr, "%s\n", msg);
abort();
}
static void *
gmp_default_alloc (size_t size)
{
void *p;
assert (size > 0);
p = malloc (size);
if (!p)
gmp_die("gmp_default_alloc: Virtual memory exhausted.");
return p;
}
static void *
gmp_default_realloc (void *old, size_t unused_old_size, size_t new_size)
{
void * p;
p = realloc (old, new_size);
if (!p)
gmp_die("gmp_default_realloc: Virtual memory exhausted.");
return p;
}
static void
gmp_default_free (void *p, size_t unused_size)
{
free (p);
}
static void * (*gmp_allocate_func) (size_t) = gmp_default_alloc;
static void * (*gmp_reallocate_func) (void *, size_t, size_t) = gmp_default_realloc;
static void (*gmp_free_func) (void *, size_t) = gmp_default_free;
void
mp_get_memory_functions (void *(**alloc_func) (size_t),
void *(**realloc_func) (void *, size_t, size_t),
void (**free_func) (void *, size_t))
{
if (alloc_func)
*alloc_func = gmp_allocate_func;
if (realloc_func)
*realloc_func = gmp_reallocate_func;
if (free_func)
*free_func = gmp_free_func;
}
void
mp_set_memory_functions (void *(*alloc_func) (size_t),
void *(*realloc_func) (void *, size_t, size_t),
void (*free_func) (void *, size_t))
{
if (!alloc_func)
alloc_func = gmp_default_alloc;
if (!realloc_func)
realloc_func = gmp_default_realloc;
if (!free_func)
free_func = gmp_default_free;
gmp_allocate_func = alloc_func;
gmp_reallocate_func = realloc_func;
gmp_free_func = free_func;
}
#define gmp_alloc(size) ((*gmp_allocate_func)((size)))
#define gmp_free(p, size) ((*gmp_free_func) ((p), (size)))
#define gmp_realloc(ptr, old_size, size) ((*gmp_reallocate_func)(ptr, old_size, size))
static mp_ptr
gmp_alloc_limbs (mp_size_t size)
{
return (mp_ptr) gmp_alloc (size * sizeof (mp_limb_t));
}
static mp_ptr
gmp_realloc_limbs (mp_ptr old, mp_size_t old_size, mp_size_t size)
{
assert (size > 0);
return (mp_ptr) gmp_realloc (old, old_size * sizeof (mp_limb_t), size * sizeof (mp_limb_t));
}
static void
gmp_free_limbs (mp_ptr old, mp_size_t size)
{
gmp_free (old, size * sizeof (mp_limb_t));
}
/* MPN interface */
void
mpn_copyi (mp_ptr d, mp_srcptr s, mp_size_t n)
{
mp_size_t i;
for (i = 0; i < n; i++)
d[i] = s[i];
}
void
mpn_copyd (mp_ptr d, mp_srcptr s, mp_size_t n)
{
while (--n >= 0)
d[n] = s[n];
}
int
mpn_cmp (mp_srcptr ap, mp_srcptr bp, mp_size_t n)
{
while (--n >= 0)
{
if (ap[n] != bp[n])
return ap[n] > bp[n] ? 1 : -1;
}
return 0;
}
static int
mpn_cmp4 (mp_srcptr ap, mp_size_t an, mp_srcptr bp, mp_size_t bn)
{
if (an != bn)
return an < bn ? -1 : 1;
else
return mpn_cmp (ap, bp, an);
}
static mp_size_t
mpn_normalized_size (mp_srcptr xp, mp_size_t n)
{
while (n > 0 && xp[n-1] == 0)
--n;
return n;
}
int
mpn_zero_p(mp_srcptr rp, mp_size_t n)
{
return mpn_normalized_size (rp, n) == 0;
}
void
mpn_zero (mp_ptr rp, mp_size_t n)
{
while (--n >= 0)
rp[n] = 0;
}
mp_limb_t
mpn_add_1 (mp_ptr rp, mp_srcptr ap, mp_size_t n, mp_limb_t b)
{
mp_size_t i;
assert (n > 0);
i = 0;
do
{
mp_limb_t r = ap[i] + b;
/* Carry out */
b = (r < b);
rp[i] = r;
}
while (++i < n);
return b;
}
mp_limb_t
mpn_add_n (mp_ptr rp, mp_srcptr ap, mp_srcptr bp, mp_size_t n)
{
mp_size_t i;
mp_limb_t cy;
for (i = 0, cy = 0; i < n; i++)
{
mp_limb_t a, b, r;
a = ap[i]; b = bp[i];
r = a + cy;
cy = (r < cy);
r += b;
cy += (r < b);
rp[i] = r;
}
return cy;
}
mp_limb_t
mpn_add (mp_ptr rp, mp_srcptr ap, mp_size_t an, mp_srcptr bp, mp_size_t bn)
{
mp_limb_t cy;
assert (an >= bn);
cy = mpn_add_n (rp, ap, bp, bn);
if (an > bn)
cy = mpn_add_1 (rp + bn, ap + bn, an - bn, cy);
return cy;
}
mp_limb_t
mpn_sub_1 (mp_ptr rp, mp_srcptr ap, mp_size_t n, mp_limb_t b)
{
mp_size_t i;
assert (n > 0);
i = 0;
do
{
mp_limb_t a = ap[i];
/* Carry out */
mp_limb_t cy = a < b;
rp[i] = a - b;
b = cy;
}
while (++i < n);
return b;
}
mp_limb_t
mpn_sub_n (mp_ptr rp, mp_srcptr ap, mp_srcptr bp, mp_size_t n)
{
mp_size_t i;
mp_limb_t cy;
for (i = 0, cy = 0; i < n; i++)
{
mp_limb_t a, b;
a = ap[i]; b = bp[i];
b += cy;
cy = (b < cy);
cy += (a < b);
rp[i] = a - b;
}
return cy;
}
mp_limb_t
mpn_sub (mp_ptr rp, mp_srcptr ap, mp_size_t an, mp_srcptr bp, mp_size_t bn)
{
mp_limb_t cy;
assert (an >= bn);
cy = mpn_sub_n (rp, ap, bp, bn);
if (an > bn)
cy = mpn_sub_1 (rp + bn, ap + bn, an - bn, cy);
return cy;
}
mp_limb_t
mpn_mul_1 (mp_ptr rp, mp_srcptr up, mp_size_t n, mp_limb_t vl)
{
mp_limb_t ul, cl, hpl, lpl;
assert (n >= 1);
cl = 0;
do
{
ul = *up++;
gmp_umul_ppmm (hpl, lpl, ul, vl);
lpl += cl;
cl = (lpl < cl) + hpl;
*rp++ = lpl;
}
while (--n != 0);
return cl;
}
mp_limb_t
mpn_addmul_1 (mp_ptr rp, mp_srcptr up, mp_size_t n, mp_limb_t vl)
{
mp_limb_t ul, cl, hpl, lpl, rl;
assert (n >= 1);
cl = 0;
do
{
ul = *up++;
gmp_umul_ppmm (hpl, lpl, ul, vl);
lpl += cl;
cl = (lpl < cl) + hpl;
rl = *rp;
lpl = rl + lpl;
cl += lpl < rl;
*rp++ = lpl;
}
while (--n != 0);
return cl;
}
mp_limb_t
mpn_submul_1 (mp_ptr rp, mp_srcptr up, mp_size_t n, mp_limb_t vl)
{
mp_limb_t ul, cl, hpl, lpl, rl;
assert (n >= 1);
cl = 0;
do
{
ul = *up++;
gmp_umul_ppmm (hpl, lpl, ul, vl);
lpl += cl;
cl = (lpl < cl) + hpl;
rl = *rp;
lpl = rl - lpl;
cl += lpl > rl;
*rp++ = lpl;
}
while (--n != 0);
return cl;
}
mp_limb_t
mpn_mul (mp_ptr rp, mp_srcptr up, mp_size_t un, mp_srcptr vp, mp_size_t vn)
{
assert (un >= vn);
assert (vn >= 1);
assert (!GMP_MPN_OVERLAP_P(rp, un + vn, up, un));
assert (!GMP_MPN_OVERLAP_P(rp, un + vn, vp, vn));
/* We first multiply by the low order limb. This result can be
stored, not added, to rp. We also avoid a loop for zeroing this
way. */
rp[un] = mpn_mul_1 (rp, up, un, vp[0]);
/* Now accumulate the product of up[] and the next higher limb from
vp[]. */
while (--vn >= 1)
{
rp += 1, vp += 1;
rp[un] = mpn_addmul_1 (rp, up, un, vp[0]);
}
return rp[un];
}
void
mpn_mul_n (mp_ptr rp, mp_srcptr ap, mp_srcptr bp, mp_size_t n)
{
mpn_mul (rp, ap, n, bp, n);
}
void
mpn_sqr (mp_ptr rp, mp_srcptr ap, mp_size_t n)
{
mpn_mul (rp, ap, n, ap, n);
}
mp_limb_t
mpn_lshift (mp_ptr rp, mp_srcptr up, mp_size_t n, unsigned int cnt)
{
mp_limb_t high_limb, low_limb;
unsigned int tnc;
mp_limb_t retval;
assert (n >= 1);
assert (cnt >= 1);
assert (cnt < GMP_LIMB_BITS);
up += n;
rp += n;
tnc = GMP_LIMB_BITS - cnt;
low_limb = *--up;
retval = low_limb >> tnc;
high_limb = (low_limb << cnt);
while (--n != 0)
{
low_limb = *--up;
*--rp = high_limb | (low_limb >> tnc);
high_limb = (low_limb << cnt);
}
*--rp = high_limb;
return retval;
}
mp_limb_t
mpn_rshift (mp_ptr rp, mp_srcptr up, mp_size_t n, unsigned int cnt)
{
mp_limb_t high_limb, low_limb;
unsigned int tnc;
mp_limb_t retval;
assert (n >= 1);
assert (cnt >= 1);
assert (cnt < GMP_LIMB_BITS);
tnc = GMP_LIMB_BITS - cnt;
high_limb = *up++;
retval = (high_limb << tnc);
low_limb = high_limb >> cnt;
while (--n != 0)
{
high_limb = *up++;
*rp++ = low_limb | (high_limb << tnc);
low_limb = high_limb >> cnt;
}
*rp = low_limb;
return retval;
}
static mp_bitcnt_t
mpn_common_scan (mp_limb_t limb, mp_size_t i, mp_srcptr up, mp_size_t un,
mp_limb_t ux)
{
unsigned cnt;
assert (ux == 0 || ux == GMP_LIMB_MAX);
assert (0 <= i && i <= un );
while (limb == 0)
{
i++;
if (i == un)
return (ux == 0 ? ~(mp_bitcnt_t) 0 : un * GMP_LIMB_BITS);
limb = ux ^ up[i];
}
gmp_ctz (cnt, limb);
return (mp_bitcnt_t) i * GMP_LIMB_BITS + cnt;
}
mp_bitcnt_t
mpn_scan1 (mp_srcptr ptr, mp_bitcnt_t bit)
{
mp_size_t i;
i = bit / GMP_LIMB_BITS;
return mpn_common_scan ( ptr[i] & (GMP_LIMB_MAX << (bit % GMP_LIMB_BITS)),
i, ptr, i, 0);
}
mp_bitcnt_t
mpn_scan0 (mp_srcptr ptr, mp_bitcnt_t bit)
{
mp_size_t i;
i = bit / GMP_LIMB_BITS;
return mpn_common_scan (~ptr[i] & (GMP_LIMB_MAX << (bit % GMP_LIMB_BITS)),
i, ptr, i, GMP_LIMB_MAX);
}
void
mpn_com (mp_ptr rp, mp_srcptr up, mp_size_t n)
{
while (--n >= 0)
*rp++ = ~ *up++;
}
mp_limb_t
mpn_neg (mp_ptr rp, mp_srcptr up, mp_size_t n)
{
while (*up == 0)
{
*rp = 0;
if (!--n)
return 0;
++up; ++rp;
}
*rp = - *up;
mpn_com (++rp, ++up, --n);
return 1;
}
/* MPN division interface. */
/* The 3/2 inverse is defined as
m = floor( (B^3-1) / (B u1 + u0)) - B
*/
mp_limb_t
mpn_invert_3by2 (mp_limb_t u1, mp_limb_t u0)
{
mp_limb_t r, m;
{
mp_limb_t p, ql;
unsigned ul, uh, qh;
assert (sizeof (unsigned) * 2 >= sizeof (mp_limb_t));
/* For notation, let b denote the half-limb base, so that B = b^2.
Split u1 = b uh + ul. */
ul = u1 & GMP_LLIMB_MASK;
uh = u1 >> (GMP_LIMB_BITS / 2);
/* Approximation of the high half of quotient. Differs from the 2/1
inverse of the half limb uh, since we have already subtracted
u0. */
qh = (u1 ^ GMP_LIMB_MAX) / uh;
/* Adjust to get a half-limb 3/2 inverse, i.e., we want
qh' = floor( (b^3 - 1) / u) - b = floor ((b^3 - b u - 1) / u
= floor( (b (~u) + b-1) / u),
and the remainder
r = b (~u) + b-1 - qh (b uh + ul)
= b (~u - qh uh) + b-1 - qh ul
Subtraction of qh ul may underflow, which implies adjustments.
But by normalization, 2 u >= B > qh ul, so we need to adjust by
at most 2.
*/
r = ((~u1 - (mp_limb_t) qh * uh) << (GMP_LIMB_BITS / 2)) | GMP_LLIMB_MASK;
p = (mp_limb_t) qh * ul;
/* Adjustment steps taken from udiv_qrnnd_c */
if (r < p)
{
qh--;
r += u1;
if (r >= u1) /* i.e. we didn't get carry when adding to r */
if (r < p)
{
qh--;
r += u1;
}
}
r -= p;
/* Low half of the quotient is
ql = floor ( (b r + b-1) / u1).
This is a 3/2 division (on half-limbs), for which qh is a
suitable inverse. */
p = (r >> (GMP_LIMB_BITS / 2)) * qh + r;
/* Unlike full-limb 3/2, we can add 1 without overflow. For this to
work, it is essential that ql is a full mp_limb_t. */
ql = (p >> (GMP_LIMB_BITS / 2)) + 1;
/* By the 3/2 trick, we don't need the high half limb. */
r = (r << (GMP_LIMB_BITS / 2)) + GMP_LLIMB_MASK - ql * u1;
if (r >= (GMP_LIMB_MAX & (p << (GMP_LIMB_BITS / 2))))
{
ql--;
r += u1;
}
m = ((mp_limb_t) qh << (GMP_LIMB_BITS / 2)) + ql;
if (r >= u1)
{
m++;
r -= u1;
}
}
/* Now m is the 2/1 inverse of u1. If u0 > 0, adjust it to become a
3/2 inverse. */
if (u0 > 0)
{
mp_limb_t th, tl;
r = ~r;
r += u0;
if (r < u0)
{
m--;
if (r >= u1)
{
m--;
r -= u1;
}
r -= u1;
}
gmp_umul_ppmm (th, tl, u0, m);
r += th;
if (r < th)
{
m--;
m -= ((r > u1) | ((r == u1) & (tl > u0)));
}
}
return m;
}
struct gmp_div_inverse
{
/* Normalization shift count. */
unsigned shift;
/* Normalized divisor (d0 unused for mpn_div_qr_1) */
mp_limb_t d1, d0;
/* Inverse, for 2/1 or 3/2. */
mp_limb_t di;
};
static void
mpn_div_qr_1_invert (struct gmp_div_inverse *inv, mp_limb_t d)
{
unsigned shift;
assert (d > 0);
gmp_clz (shift, d);
inv->shift = shift;
inv->d1 = d << shift;
inv->di = mpn_invert_limb (inv->d1);
}
static void
mpn_div_qr_2_invert (struct gmp_div_inverse *inv,
mp_limb_t d1, mp_limb_t d0)
{
unsigned shift;
assert (d1 > 0);
gmp_clz (shift, d1);
inv->shift = shift;
if (shift > 0)
{
d1 = (d1 << shift) | (d0 >> (GMP_LIMB_BITS - shift));
d0 <<= shift;
}
inv->d1 = d1;
inv->d0 = d0;
inv->di = mpn_invert_3by2 (d1, d0);
}
static void
mpn_div_qr_invert (struct gmp_div_inverse *inv,
mp_srcptr dp, mp_size_t dn)
{
assert (dn > 0);
if (dn == 1)
mpn_div_qr_1_invert (inv, dp[0]);
else if (dn == 2)
mpn_div_qr_2_invert (inv, dp[1], dp[0]);
else
{
unsigned shift;
mp_limb_t d1, d0;
d1 = dp[dn-1];
d0 = dp[dn-2];
assert (d1 > 0);
gmp_clz (shift, d1);
inv->shift = shift;
if (shift > 0)
{
d1 = (d1 << shift) | (d0 >> (GMP_LIMB_BITS - shift));
d0 = (d0 << shift) | (dp[dn-3] >> (GMP_LIMB_BITS - shift));
}
inv->d1 = d1;
inv->d0 = d0;
inv->di = mpn_invert_3by2 (d1, d0);
}
}
/* Not matching current public gmp interface, rather corresponding to
the sbpi1_div_* functions. */
static mp_limb_t
mpn_div_qr_1_preinv (mp_ptr qp, mp_srcptr np, mp_size_t nn,
const struct gmp_div_inverse *inv)
{
mp_limb_t d, di;
mp_limb_t r;
mp_ptr tp = NULL;
mp_size_t tn = 0;
if (inv->shift > 0)
{
/* Shift, reusing qp area if possible. In-place shift if qp == np. */
tp = qp;
if (!tp)
{
tn = nn;
tp = gmp_alloc_limbs (tn);
}
r = mpn_lshift (tp, np, nn, inv->shift);
np = tp;
}
else
r = 0;
d = inv->d1;
di = inv->di;
while (--nn >= 0)
{
mp_limb_t q;
gmp_udiv_qrnnd_preinv (q, r, r, np[nn], d, di);
if (qp)
qp[nn] = q;
}
if (tn)
gmp_free_limbs (tp, tn);
return r >> inv->shift;
}
static void
mpn_div_qr_2_preinv (mp_ptr qp, mp_ptr np, mp_size_t nn,
const struct gmp_div_inverse *inv)
{
unsigned shift;
mp_size_t i;
mp_limb_t d1, d0, di, r1, r0;
assert (nn >= 2);
shift = inv->shift;
d1 = inv->d1;
d0 = inv->d0;
di = inv->di;
if (shift > 0)
r1 = mpn_lshift (np, np, nn, shift);
else
r1 = 0;
r0 = np[nn - 1];
i = nn - 2;
do
{
mp_limb_t n0, q;
n0 = np[i];
gmp_udiv_qr_3by2 (q, r1, r0, r1, r0, n0, d1, d0, di);
if (qp)
qp[i] = q;
}
while (--i >= 0);
if (shift > 0)
{
assert ((r0 & (GMP_LIMB_MAX >> (GMP_LIMB_BITS - shift))) == 0);
r0 = (r0 >> shift) | (r1 << (GMP_LIMB_BITS - shift));
r1 >>= shift;
}
np[1] = r1;
np[0] = r0;
}
static void
mpn_div_qr_pi1 (mp_ptr qp,
mp_ptr np, mp_size_t nn, mp_limb_t n1,
mp_srcptr dp, mp_size_t dn,
mp_limb_t dinv)
{
mp_size_t i;
mp_limb_t d1, d0;
mp_limb_t cy, cy1;
mp_limb_t q;
assert (dn > 2);
assert (nn >= dn);
d1 = dp[dn - 1];
d0 = dp[dn - 2];
assert ((d1 & GMP_LIMB_HIGHBIT) != 0);
/* Iteration variable is the index of the q limb.
*
* We divide <n1, np[dn-1+i], np[dn-2+i], np[dn-3+i],..., np[i]>
* by <d1, d0, dp[dn-3], ..., dp[0] >
*/
i = nn - dn;
do
{
mp_limb_t n0 = np[dn-1+i];
if (n1 == d1 && n0 == d0)
{
q = GMP_LIMB_MAX;
mpn_submul_1 (np+i, dp, dn, q);
n1 = np[dn-1+i]; /* update n1, last loop's value will now be invalid */
}
else
{
gmp_udiv_qr_3by2 (q, n1, n0, n1, n0, np[dn-2+i], d1, d0, dinv);
cy = mpn_submul_1 (np + i, dp, dn-2, q);
cy1 = n0 < cy;
n0 = n0 - cy;
cy = n1 < cy1;
n1 = n1 - cy1;
np[dn-2+i] = n0;
if (cy != 0)
{
n1 += d1 + mpn_add_n (np + i, np + i, dp, dn - 1);
q--;
}
}
if (qp)
qp[i] = q;
}
while (--i >= 0);
np[dn - 1] = n1;
}
static void
mpn_div_qr_preinv (mp_ptr qp, mp_ptr np, mp_size_t nn,
mp_srcptr dp, mp_size_t dn,
const struct gmp_div_inverse *inv)
{
assert (dn > 0);
assert (nn >= dn);
if (dn == 1)
np[0] = mpn_div_qr_1_preinv (qp, np, nn, inv);
else if (dn == 2)
mpn_div_qr_2_preinv (qp, np, nn, inv);
else
{
mp_limb_t nh;
unsigned shift;
assert (inv->d1 == dp[dn-1]);
assert (inv->d0 == dp[dn-2]);
assert ((inv->d1 & GMP_LIMB_HIGHBIT) != 0);
shift = inv->shift;
if (shift > 0)
nh = mpn_lshift (np, np, nn, shift);
else
nh = 0;
mpn_div_qr_pi1 (qp, np, nn, nh, dp, dn, inv->di);
if (shift > 0)
gmp_assert_nocarry (mpn_rshift (np, np, dn, shift));
}
}
static void
mpn_div_qr (mp_ptr qp, mp_ptr np, mp_size_t nn, mp_srcptr dp, mp_size_t dn)
{
struct gmp_div_inverse inv;
mp_ptr tp = NULL;
assert (dn > 0);
assert (nn >= dn);
mpn_div_qr_invert (&inv, dp, dn);
if (dn > 2 && inv.shift > 0)
{
tp = gmp_alloc_limbs (dn);
gmp_assert_nocarry (mpn_lshift (tp, dp, dn, inv.shift));
dp = tp;
}
mpn_div_qr_preinv (qp, np, nn, dp, dn, &inv);
if (tp)
gmp_free_limbs (tp, dn);
}
/* MPN base conversion. */
static unsigned
mpn_base_power_of_two_p (unsigned b)
{
switch (b)
{
case 2: return 1;
case 4: return 2;
case 8: return 3;
case 16: return 4;
case 32: return 5;
case 64: return 6;
case 128: return 7;
case 256: return 8;
default: return 0;
}
}
struct mpn_base_info
{
/* bb is the largest power of the base which fits in one limb, and
exp is the corresponding exponent. */
unsigned exp;
mp_limb_t bb;
};
static void
mpn_get_base_info (struct mpn_base_info *info, mp_limb_t b)
{
mp_limb_t m;
mp_limb_t p;
unsigned exp;
m = GMP_LIMB_MAX / b;
for (exp = 1, p = b; p <= m; exp++)
p *= b;
info->exp = exp;
info->bb = p;
}
static mp_bitcnt_t
mpn_limb_size_in_base_2 (mp_limb_t u)
{
unsigned shift;
assert (u > 0);
gmp_clz (shift, u);
return GMP_LIMB_BITS - shift;
}
static size_t
mpn_get_str_bits (unsigned char *sp, unsigned bits, mp_srcptr up, mp_size_t un)
{
unsigned char mask;
size_t sn, j;
mp_size_t i;
unsigned shift;
sn = ((un - 1) * GMP_LIMB_BITS + mpn_limb_size_in_base_2 (up[un-1])
+ bits - 1) / bits;
mask = (1U << bits) - 1;
for (i = 0, j = sn, shift = 0; j-- > 0;)
{
unsigned char digit = up[i] >> shift;
shift += bits;
if (shift >= GMP_LIMB_BITS && ++i < un)
{
shift -= GMP_LIMB_BITS;
digit |= up[i] << (bits - shift);
}
sp[j] = digit & mask;
}
return sn;
}
/* We generate digits from the least significant end, and reverse at
the end. */
static size_t
mpn_limb_get_str (unsigned char *sp, mp_limb_t w,
const struct gmp_div_inverse *binv)
{
mp_size_t i;
for (i = 0; w > 0; i++)
{
mp_limb_t h, l, r;
h = w >> (GMP_LIMB_BITS - binv->shift);
l = w << binv->shift;
gmp_udiv_qrnnd_preinv (w, r, h, l, binv->d1, binv->di);
assert ((r & (GMP_LIMB_MAX >> (GMP_LIMB_BITS - binv->shift))) == 0);
r >>= binv->shift;
sp[i] = r;
}
return i;
}
static size_t
mpn_get_str_other (unsigned char *sp,
int base, const struct mpn_base_info *info,
mp_ptr up, mp_size_t un)
{
struct gmp_div_inverse binv;
size_t sn;
size_t i;
mpn_div_qr_1_invert (&binv, base);
sn = 0;
if (un > 1)
{
struct gmp_div_inverse bbinv;
mpn_div_qr_1_invert (&bbinv, info->bb);
do
{
mp_limb_t w;
size_t done;
w = mpn_div_qr_1_preinv (up, up, un, &bbinv);
un -= (up[un-1] == 0);
done = mpn_limb_get_str (sp + sn, w, &binv);
for (sn += done; done < info->exp; done++)
sp[sn++] = 0;
}
while (un > 1);
}
sn += mpn_limb_get_str (sp + sn, up[0], &binv);
/* Reverse order */
for (i = 0; 2*i + 1 < sn; i++)
{
unsigned char t = sp[i];
sp[i] = sp[sn - i - 1];
sp[sn - i - 1] = t;
}
return sn;
}
size_t
mpn_get_str (unsigned char *sp, int base, mp_ptr up, mp_size_t un)
{
unsigned bits;
assert (un > 0);
assert (up[un-1] > 0);
bits = mpn_base_power_of_two_p (base);
if (bits)
return mpn_get_str_bits (sp, bits, up, un);
else
{
struct mpn_base_info info;
mpn_get_base_info (&info, base);
return mpn_get_str_other (sp, base, &info, up, un);
}
}
static mp_size_t
mpn_set_str_bits (mp_ptr rp, const unsigned char *sp, size_t sn,
unsigned bits)
{
mp_size_t rn;
mp_limb_t limb;
unsigned shift;
for (limb = 0, rn = 0, shift = 0; sn-- > 0; )
{
limb |= (mp_limb_t) sp[sn] << shift;
shift += bits;
if (shift >= GMP_LIMB_BITS)
{
shift -= GMP_LIMB_BITS;
rp[rn++] = limb;
/* Next line is correct also if shift == 0,
bits == 8, and mp_limb_t == unsigned char. */
limb = (unsigned int) sp[sn] >> (bits - shift);
}
}
if (limb != 0)
rp[rn++] = limb;
else
rn = mpn_normalized_size (rp, rn);
return rn;
}
/* Result is usually normalized, except for all-zero input, in which
case a single zero limb is written at *RP, and 1 is returned. */
static mp_size_t
mpn_set_str_other (mp_ptr rp, const unsigned char *sp, size_t sn,
mp_limb_t b, const struct mpn_base_info *info)
{
mp_size_t rn;
mp_limb_t w;
unsigned k;
size_t j;
assert (sn > 0);
k = 1 + (sn - 1) % info->exp;
j = 0;
w = sp[j++];
while (--k != 0)
w = w * b + sp[j++];
rp[0] = w;
for (rn = 1; j < sn;)
{
mp_limb_t cy;
w = sp[j++];
for (k = 1; k < info->exp; k++)
w = w * b + sp[j++];
cy = mpn_mul_1 (rp, rp, rn, info->bb);
cy += mpn_add_1 (rp, rp, rn, w);
if (cy > 0)
rp[rn++] = cy;
}
assert (j == sn);
return rn;
}
mp_size_t
mpn_set_str (mp_ptr rp, const unsigned char *sp, size_t sn, int base)
{
unsigned bits;
if (sn == 0)
return 0;
bits = mpn_base_power_of_two_p (base);
if (bits)
return mpn_set_str_bits (rp, sp, sn, bits);
else
{
struct mpn_base_info info;
mpn_get_base_info (&info, base);
return mpn_set_str_other (rp, sp, sn, base, &info);
}
}
/* MPZ interface */
void
mpz_init (mpz_t r)
{
static const mp_limb_t dummy_limb = GMP_LIMB_MAX & 0xc1a0;
r->_mp_alloc = 0;
r->_mp_size = 0;
r->_mp_d = (mp_ptr) &dummy_limb;
}
/* The utility of this function is a bit limited, since many functions
assigns the result variable using mpz_swap. */
void
mpz_init2 (mpz_t r, mp_bitcnt_t bits)
{
mp_size_t rn;
bits -= (bits != 0); /* Round down, except if 0 */
rn = 1 + bits / GMP_LIMB_BITS;
r->_mp_alloc = rn;
r->_mp_size = 0;
r->_mp_d = gmp_alloc_limbs (rn);
}
void
mpz_clear (mpz_t r)
{
if (r->_mp_alloc)
gmp_free_limbs (r->_mp_d, r->_mp_alloc);
}
static mp_ptr
mpz_realloc (mpz_t r, mp_size_t size)
{
size = GMP_MAX (size, 1);
if (r->_mp_alloc)
r->_mp_d = gmp_realloc_limbs (r->_mp_d, r->_mp_alloc, size);
else
r->_mp_d = gmp_alloc_limbs (size);
r->_mp_alloc = size;
if (GMP_ABS (r->_mp_size) > size)
r->_mp_size = 0;
return r->_mp_d;
}
/* Realloc for an mpz_t WHAT if it has less than NEEDED limbs. */
#define MPZ_REALLOC(z,n) ((n) > (z)->_mp_alloc \
? mpz_realloc(z,n) \
: (z)->_mp_d)
/* MPZ assignment and basic conversions. */
void
mpz_set_si (mpz_t r, signed long int x)
{
if (x >= 0)
mpz_set_ui (r, x);
else /* (x < 0) */
if (GMP_LIMB_BITS < GMP_ULONG_BITS)
{
mpz_set_ui (r, GMP_NEG_CAST (unsigned long int, x));
mpz_neg (r, r);
}
else
{
r->_mp_size = -1;
MPZ_REALLOC (r, 1)[0] = GMP_NEG_CAST (unsigned long int, x);
}
}
void
mpz_set_ui (mpz_t r, unsigned long int x)
{
if (x > 0)
{
r->_mp_size = 1;
MPZ_REALLOC (r, 1)[0] = x;
if (GMP_LIMB_BITS < GMP_ULONG_BITS)
{
int LOCAL_GMP_LIMB_BITS = GMP_LIMB_BITS;
while (x >>= LOCAL_GMP_LIMB_BITS)
{
++ r->_mp_size;
MPZ_REALLOC (r, r->_mp_size)[r->_mp_size - 1] = x;
}
}
}
else
r->_mp_size = 0;
}
void
mpz_set (mpz_t r, const mpz_t x)
{
/* Allow the NOP r == x */
if (r != x)
{
mp_size_t n;
mp_ptr rp;
n = GMP_ABS (x->_mp_size);
rp = MPZ_REALLOC (r, n);
mpn_copyi (rp, x->_mp_d, n);
r->_mp_size = x->_mp_size;
}
}
void
mpz_init_set_si (mpz_t r, signed long int x)
{
mpz_init (r);
mpz_set_si (r, x);
}
void
mpz_init_set_ui (mpz_t r, unsigned long int x)
{
mpz_init (r);
mpz_set_ui (r, x);
}
void
mpz_init_set (mpz_t r, const mpz_t x)
{
mpz_init (r);
mpz_set (r, x);
}
int
mpz_fits_slong_p (const mpz_t u)
{
return mpz_cmp_si (u, LONG_MAX) <= 0 && mpz_cmp_si (u, LONG_MIN) >= 0;
}
static int
mpn_absfits_ulong_p (mp_srcptr up, mp_size_t un)
{
int ulongsize = GMP_ULONG_BITS / GMP_LIMB_BITS;
mp_limb_t ulongrem = 0;
if (GMP_ULONG_BITS % GMP_LIMB_BITS != 0)
ulongrem = (mp_limb_t) (ULONG_MAX >> GMP_LIMB_BITS * ulongsize) + 1;
return un <= ulongsize || (up[ulongsize] < ulongrem && un == ulongsize + 1);
}
int
mpz_fits_ulong_p (const mpz_t u)
{
mp_size_t us = u->_mp_size;
return us >= 0 && mpn_absfits_ulong_p (u->_mp_d, us);
}
int
mpz_fits_sint_p (const mpz_t u)
{
return mpz_cmp_si (u, INT_MAX) <= 0 && mpz_cmp_si (u, INT_MIN) >= 0;
}
int
mpz_fits_uint_p (const mpz_t u)
{
return u->_mp_size >= 0 && mpz_cmpabs_ui (u, UINT_MAX) <= 0;
}
int
mpz_fits_sshort_p (const mpz_t u)
{
return mpz_cmp_si (u, SHRT_MAX) <= 0 && mpz_cmp_si (u, SHRT_MIN) >= 0;
}
int
mpz_fits_ushort_p (const mpz_t u)
{
return u->_mp_size >= 0 && mpz_cmpabs_ui (u, USHRT_MAX) <= 0;
}
long int
mpz_get_si (const mpz_t u)
{
unsigned long r = mpz_get_ui (u);
unsigned long c = -LONG_MAX - LONG_MIN;
if (u->_mp_size < 0)
/* This expression is necessary to properly handle -LONG_MIN */
return -(long) c - (long) ((r - c) & LONG_MAX);
else
return (long) (r & LONG_MAX);
}
unsigned long int
mpz_get_ui (const mpz_t u)
{
if (GMP_LIMB_BITS < GMP_ULONG_BITS)
{
int LOCAL_GMP_LIMB_BITS = GMP_LIMB_BITS;
unsigned long r = 0;
mp_size_t n = GMP_ABS (u->_mp_size);
n = GMP_MIN (n, 1 + (mp_size_t) (GMP_ULONG_BITS - 1) / GMP_LIMB_BITS);
while (--n >= 0)
r = (r << LOCAL_GMP_LIMB_BITS) + u->_mp_d[n];
return r;
}
return u->_mp_size == 0 ? 0 : u->_mp_d[0];
}
size_t
mpz_size (const mpz_t u)
{
return GMP_ABS (u->_mp_size);
}
mp_limb_t
mpz_getlimbn (const mpz_t u, mp_size_t n)
{
if (n >= 0 && n < GMP_ABS (u->_mp_size))
return u->_mp_d[n];
else
return 0;
}
void
mpz_realloc2 (mpz_t x, mp_bitcnt_t n)
{
mpz_realloc (x, 1 + (n - (n != 0)) / GMP_LIMB_BITS);
}
mp_srcptr
mpz_limbs_read (mpz_srcptr x)
{
return x->_mp_d;
}
mp_ptr
mpz_limbs_modify (mpz_t x, mp_size_t n)
{
assert (n > 0);
return MPZ_REALLOC (x, n);
}
mp_ptr
mpz_limbs_write (mpz_t x, mp_size_t n)
{
return mpz_limbs_modify (x, n);
}
void
mpz_limbs_finish (mpz_t x, mp_size_t xs)
{
mp_size_t xn;
xn = mpn_normalized_size (x->_mp_d, GMP_ABS (xs));
x->_mp_size = xs < 0 ? -xn : xn;
}
static mpz_srcptr
mpz_roinit_normal_n (mpz_t x, mp_srcptr xp, mp_size_t xs)
{
x->_mp_alloc = 0;
x->_mp_d = (mp_ptr) xp;
x->_mp_size = xs;
return x;
}
mpz_srcptr
mpz_roinit_n (mpz_t x, mp_srcptr xp, mp_size_t xs)
{
mpz_roinit_normal_n (x, xp, xs);
mpz_limbs_finish (x, xs);
return x;
}
/* Conversions and comparison to double. */
void
mpz_set_d (mpz_t r, double x)
{
int sign;
mp_ptr rp;
mp_size_t rn, i;
double B;
double Bi;
mp_limb_t f;
/* x != x is true when x is a NaN, and x == x * 0.5 is true when x is
zero or infinity. */
if (x != x || x == x * 0.5)
{
r->_mp_size = 0;
return;
}
sign = x < 0.0 ;
if (sign)
x = - x;
if (x < 1.0)
{
r->_mp_size = 0;
return;
}
B = 4.0 * (double) (GMP_LIMB_HIGHBIT >> 1);
Bi = 1.0 / B;
for (rn = 1; x >= B; rn++)
x *= Bi;
rp = MPZ_REALLOC (r, rn);
f = (mp_limb_t) x;
x -= f;
assert (x < 1.0);
i = rn-1;
rp[i] = f;
while (--i >= 0)
{
x = B * x;
f = (mp_limb_t) x;
x -= f;
assert (x < 1.0);
rp[i] = f;
}
r->_mp_size = sign ? - rn : rn;
}
void
mpz_init_set_d (mpz_t r, double x)
{
mpz_init (r);
mpz_set_d (r, x);
}
double
mpz_get_d (const mpz_t u)
{
int m;
mp_limb_t l;
mp_size_t un;
double x;
double B = 4.0 * (double) (GMP_LIMB_HIGHBIT >> 1);
un = GMP_ABS (u->_mp_size);
if (un == 0)
return 0.0;
l = u->_mp_d[--un];
gmp_clz (m, l);
m = m + GMP_DBL_MANT_BITS - GMP_LIMB_BITS;
if (m < 0)
l &= GMP_LIMB_MAX << -m;
for (x = l; --un >= 0;)
{
x = B*x;
if (m > 0) {
l = u->_mp_d[un];
m -= GMP_LIMB_BITS;
if (m < 0)
l &= GMP_LIMB_MAX << -m;
x += l;
}
}
if (u->_mp_size < 0)
x = -x;
return x;
}
int
mpz_cmpabs_d (const mpz_t x, double d)
{
mp_size_t xn;
double B, Bi;
mp_size_t i;
xn = x->_mp_size;
d = GMP_ABS (d);
if (xn != 0)
{
xn = GMP_ABS (xn);
B = 4.0 * (double) (GMP_LIMB_HIGHBIT >> 1);
Bi = 1.0 / B;
/* Scale d so it can be compared with the top limb. */
for (i = 1; i < xn; i++)
d *= Bi;
if (d >= B)
return -1;
/* Compare floor(d) to top limb, subtract and cancel when equal. */
for (i = xn; i-- > 0;)
{
mp_limb_t f, xl;
f = (mp_limb_t) d;
xl = x->_mp_d[i];
if (xl > f)
return 1;
else if (xl < f)
return -1;
d = B * (d - f);
}
}
return - (d > 0.0);
}
int
mpz_cmp_d (const mpz_t x, double d)
{
if (x->_mp_size < 0)
{
if (d >= 0.0)
return -1;
else
return -mpz_cmpabs_d (x, d);
}
else
{
if (d < 0.0)
return 1;
else
return mpz_cmpabs_d (x, d);
}
}
/* MPZ comparisons and the like. */
int
mpz_sgn (const mpz_t u)
{
return GMP_CMP (u->_mp_size, 0);
}
int
mpz_cmp_si (const mpz_t u, long v)
{
mp_size_t usize = u->_mp_size;
if (v >= 0)
return mpz_cmp_ui (u, v);
else if (usize >= 0)
return 1;
else
return - mpz_cmpabs_ui (u, GMP_NEG_CAST (unsigned long int, v));
}
int
mpz_cmp_ui (const mpz_t u, unsigned long v)
{
mp_size_t usize = u->_mp_size;
if (usize < 0)
return -1;
else
return mpz_cmpabs_ui (u, v);
}
int
mpz_cmp (const mpz_t a, const mpz_t b)
{
mp_size_t asize = a->_mp_size;
mp_size_t bsize = b->_mp_size;
if (asize != bsize)
return (asize < bsize) ? -1 : 1;
else if (asize >= 0)
return mpn_cmp (a->_mp_d, b->_mp_d, asize);
else
return mpn_cmp (b->_mp_d, a->_mp_d, -asize);
}
int
mpz_cmpabs_ui (const mpz_t u, unsigned long v)
{
mp_size_t un = GMP_ABS (u->_mp_size);
if (! mpn_absfits_ulong_p (u->_mp_d, un))
return 1;
else
{
unsigned long uu = mpz_get_ui (u);
return GMP_CMP(uu, v);
}
}
int
mpz_cmpabs (const mpz_t u, const mpz_t v)
{
return mpn_cmp4 (u->_mp_d, GMP_ABS (u->_mp_size),
v->_mp_d, GMP_ABS (v->_mp_size));
}
void
mpz_abs (mpz_t r, const mpz_t u)
{
mpz_set (r, u);
r->_mp_size = GMP_ABS (r->_mp_size);
}
void
mpz_neg (mpz_t r, const mpz_t u)
{
mpz_set (r, u);
r->_mp_size = -r->_mp_size;
}
void
mpz_swap (mpz_t u, mpz_t v)
{
MP_SIZE_T_SWAP (u->_mp_alloc, v->_mp_alloc);
MPN_PTR_SWAP (u->_mp_d, u->_mp_size, v->_mp_d, v->_mp_size);
}
/* MPZ addition and subtraction */
void
mpz_add_ui (mpz_t r, const mpz_t a, unsigned long b)
{
mpz_t bb;
mpz_init_set_ui (bb, b);
mpz_add (r, a, bb);
mpz_clear (bb);
}
void
mpz_sub_ui (mpz_t r, const mpz_t a, unsigned long b)
{
mpz_ui_sub (r, b, a);
mpz_neg (r, r);
}
void
mpz_ui_sub (mpz_t r, unsigned long a, const mpz_t b)
{
mpz_neg (r, b);
mpz_add_ui (r, r, a);
}
static mp_size_t
mpz_abs_add (mpz_t r, const mpz_t a, const mpz_t b)
{
mp_size_t an = GMP_ABS (a->_mp_size);
mp_size_t bn = GMP_ABS (b->_mp_size);
mp_ptr rp;
mp_limb_t cy;
if (an < bn)
{
MPZ_SRCPTR_SWAP (a, b);
MP_SIZE_T_SWAP (an, bn);
}
rp = MPZ_REALLOC (r, an + 1);
cy = mpn_add (rp, a->_mp_d, an, b->_mp_d, bn);
rp[an] = cy;
return an + cy;
}
static mp_size_t
mpz_abs_sub (mpz_t r, const mpz_t a, const mpz_t b)
{
mp_size_t an = GMP_ABS (a->_mp_size);
mp_size_t bn = GMP_ABS (b->_mp_size);
int cmp;
mp_ptr rp;
cmp = mpn_cmp4 (a->_mp_d, an, b->_mp_d, bn);
if (cmp > 0)
{
rp = MPZ_REALLOC (r, an);
gmp_assert_nocarry (mpn_sub (rp, a->_mp_d, an, b->_mp_d, bn));
return mpn_normalized_size (rp, an);
}
else if (cmp < 0)
{
rp = MPZ_REALLOC (r, bn);
gmp_assert_nocarry (mpn_sub (rp, b->_mp_d, bn, a->_mp_d, an));
return -mpn_normalized_size (rp, bn);
}
else
return 0;
}
void
mpz_add (mpz_t r, const mpz_t a, const mpz_t b)
{
mp_size_t rn;
if ( (a->_mp_size ^ b->_mp_size) >= 0)
rn = mpz_abs_add (r, a, b);
else
rn = mpz_abs_sub (r, a, b);
r->_mp_size = a->_mp_size >= 0 ? rn : - rn;
}
void
mpz_sub (mpz_t r, const mpz_t a, const mpz_t b)
{
mp_size_t rn;
if ( (a->_mp_size ^ b->_mp_size) >= 0)
rn = mpz_abs_sub (r, a, b);
else
rn = mpz_abs_add (r, a, b);
r->_mp_size = a->_mp_size >= 0 ? rn : - rn;
}
/* MPZ multiplication */
void
mpz_mul_si (mpz_t r, const mpz_t u, long int v)
{
if (v < 0)
{
mpz_mul_ui (r, u, GMP_NEG_CAST (unsigned long int, v));
mpz_neg (r, r);
}
else
mpz_mul_ui (r, u, v);
}
void
mpz_mul_ui (mpz_t r, const mpz_t u, unsigned long int v)
{
mpz_t vv;
mpz_init_set_ui (vv, v);
mpz_mul (r, u, vv);
mpz_clear (vv);
return;
}
void
mpz_mul (mpz_t r, const mpz_t u, const mpz_t v)
{
int sign;
mp_size_t un, vn, rn;
mpz_t t;
mp_ptr tp;
un = u->_mp_size;
vn = v->_mp_size;
if (un == 0 || vn == 0)
{
r->_mp_size = 0;
return;
}
sign = (un ^ vn) < 0;
un = GMP_ABS (un);
vn = GMP_ABS (vn);
mpz_init2 (t, (un + vn) * GMP_LIMB_BITS);
tp = t->_mp_d;
if (un >= vn)
mpn_mul (tp, u->_mp_d, un, v->_mp_d, vn);
else
mpn_mul (tp, v->_mp_d, vn, u->_mp_d, un);
rn = un + vn;
rn -= tp[rn-1] == 0;
t->_mp_size = sign ? - rn : rn;
mpz_swap (r, t);
mpz_clear (t);
}
void
mpz_mul_2exp (mpz_t r, const mpz_t u, mp_bitcnt_t bits)
{
mp_size_t un, rn;
mp_size_t limbs;
unsigned shift;
mp_ptr rp;
un = GMP_ABS (u->_mp_size);
if (un == 0)
{
r->_mp_size = 0;
return;
}
limbs = bits / GMP_LIMB_BITS;
shift = bits % GMP_LIMB_BITS;
rn = un + limbs + (shift > 0);
rp = MPZ_REALLOC (r, rn);
if (shift > 0)
{
mp_limb_t cy = mpn_lshift (rp + limbs, u->_mp_d, un, shift);
rp[rn-1] = cy;
rn -= (cy == 0);
}
else
mpn_copyd (rp + limbs, u->_mp_d, un);
mpn_zero (rp, limbs);
r->_mp_size = (u->_mp_size < 0) ? - rn : rn;
}
void
mpz_addmul_ui (mpz_t r, const mpz_t u, unsigned long int v)
{
mpz_t t;
mpz_init_set_ui (t, v);
mpz_mul (t, u, t);
mpz_add (r, r, t);
mpz_clear (t);
}
void
mpz_submul_ui (mpz_t r, const mpz_t u, unsigned long int v)
{
mpz_t t;
mpz_init_set_ui (t, v);
mpz_mul (t, u, t);
mpz_sub (r, r, t);
mpz_clear (t);
}
void
mpz_addmul (mpz_t r, const mpz_t u, const mpz_t v)
{
mpz_t t;
mpz_init (t);
mpz_mul (t, u, v);
mpz_add (r, r, t);
mpz_clear (t);
}
void
mpz_submul (mpz_t r, const mpz_t u, const mpz_t v)
{
mpz_t t;
mpz_init (t);
mpz_mul (t, u, v);
mpz_sub (r, r, t);
mpz_clear (t);
}
/* MPZ division */
enum mpz_div_round_mode { GMP_DIV_FLOOR, GMP_DIV_CEIL, GMP_DIV_TRUNC };
/* Allows q or r to be zero. Returns 1 iff remainder is non-zero. */
static int
mpz_div_qr (mpz_t q, mpz_t r,
const mpz_t n, const mpz_t d, enum mpz_div_round_mode mode)
{
mp_size_t ns, ds, nn, dn, qs;
ns = n->_mp_size;
ds = d->_mp_size;
if (ds == 0)
gmp_die("mpz_div_qr: Divide by zero.");
if (ns == 0)
{
if (q)
q->_mp_size = 0;
if (r)
r->_mp_size = 0;
return 0;
}
nn = GMP_ABS (ns);
dn = GMP_ABS (ds);
qs = ds ^ ns;
if (nn < dn)
{
if (mode == GMP_DIV_CEIL && qs >= 0)
{
/* q = 1, r = n - d */
if (r)
mpz_sub (r, n, d);
if (q)
mpz_set_ui (q, 1);
}
else if (mode == GMP_DIV_FLOOR && qs < 0)
{
/* q = -1, r = n + d */
if (r)
mpz_add (r, n, d);
if (q)
mpz_set_si (q, -1);
}
else
{
/* q = 0, r = d */
if (r)
mpz_set (r, n);
if (q)
q->_mp_size = 0;
}
return 1;
}
else
{
mp_ptr np, qp;
mp_size_t qn, rn;
mpz_t tq, tr;
mpz_init_set (tr, n);
np = tr->_mp_d;
qn = nn - dn + 1;
if (q)
{
mpz_init2 (tq, qn * GMP_LIMB_BITS);
qp = tq->_mp_d;
}
else
qp = NULL;
mpn_div_qr (qp, np, nn, d->_mp_d, dn);
if (qp)
{
qn -= (qp[qn-1] == 0);
tq->_mp_size = qs < 0 ? -qn : qn;
}
rn = mpn_normalized_size (np, dn);
tr->_mp_size = ns < 0 ? - rn : rn;
if (mode == GMP_DIV_FLOOR && qs < 0 && rn != 0)
{
if (q)
mpz_sub_ui (tq, tq, 1);
if (r)
mpz_add (tr, tr, d);
}
else if (mode == GMP_DIV_CEIL && qs >= 0 && rn != 0)
{
if (q)
mpz_add_ui (tq, tq, 1);
if (r)
mpz_sub (tr, tr, d);
}
if (q)
{
mpz_swap (tq, q);
mpz_clear (tq);
}
if (r)
mpz_swap (tr, r);
mpz_clear (tr);
return rn != 0;
}
}
void
mpz_cdiv_qr (mpz_t q, mpz_t r, const mpz_t n, const mpz_t d)
{
mpz_div_qr (q, r, n, d, GMP_DIV_CEIL);
}
void
mpz_fdiv_qr (mpz_t q, mpz_t r, const mpz_t n, const mpz_t d)
{
mpz_div_qr (q, r, n, d, GMP_DIV_FLOOR);
}
void
mpz_tdiv_qr (mpz_t q, mpz_t r, const mpz_t n, const mpz_t d)
{
mpz_div_qr (q, r, n, d, GMP_DIV_TRUNC);
}
void
mpz_cdiv_q (mpz_t q, const mpz_t n, const mpz_t d)
{
mpz_div_qr (q, NULL, n, d, GMP_DIV_CEIL);
}
void
mpz_fdiv_q (mpz_t q, const mpz_t n, const mpz_t d)
{
mpz_div_qr (q, NULL, n, d, GMP_DIV_FLOOR);
}
void
mpz_tdiv_q (mpz_t q, const mpz_t n, const mpz_t d)
{
mpz_div_qr (q, NULL, n, d, GMP_DIV_TRUNC);
}
void
mpz_cdiv_r (mpz_t r, const mpz_t n, const mpz_t d)
{
mpz_div_qr (NULL, r, n, d, GMP_DIV_CEIL);
}
void
mpz_fdiv_r (mpz_t r, const mpz_t n, const mpz_t d)
{
mpz_div_qr (NULL, r, n, d, GMP_DIV_FLOOR);
}
void
mpz_tdiv_r (mpz_t r, const mpz_t n, const mpz_t d)
{
mpz_div_qr (NULL, r, n, d, GMP_DIV_TRUNC);
}
void
mpz_mod (mpz_t r, const mpz_t n, const mpz_t d)
{
mpz_div_qr (NULL, r, n, d, d->_mp_size >= 0 ? GMP_DIV_FLOOR : GMP_DIV_CEIL);
}
static void
mpz_div_q_2exp (mpz_t q, const mpz_t u, mp_bitcnt_t bit_index,
enum mpz_div_round_mode mode)
{
mp_size_t un, qn;
mp_size_t limb_cnt;
mp_ptr qp;
int adjust;
un = u->_mp_size;
if (un == 0)
{
q->_mp_size = 0;
return;
}
limb_cnt = bit_index / GMP_LIMB_BITS;
qn = GMP_ABS (un) - limb_cnt;
bit_index %= GMP_LIMB_BITS;
if (mode == ((un > 0) ? GMP_DIV_CEIL : GMP_DIV_FLOOR)) /* un != 0 here. */
/* Note: Below, the final indexing at limb_cnt is valid because at
that point we have qn > 0. */
adjust = (qn <= 0
|| !mpn_zero_p (u->_mp_d, limb_cnt)
|| (u->_mp_d[limb_cnt]
& (((mp_limb_t) 1 << bit_index) - 1)));
else
adjust = 0;
if (qn <= 0)
qn = 0;
else
{
qp = MPZ_REALLOC (q, qn);
if (bit_index != 0)
{
mpn_rshift (qp, u->_mp_d + limb_cnt, qn, bit_index);
qn -= qp[qn - 1] == 0;
}
else
{
mpn_copyi (qp, u->_mp_d + limb_cnt, qn);
}
}
q->_mp_size = qn;
if (adjust)
mpz_add_ui (q, q, 1);
if (un < 0)
mpz_neg (q, q);
}
static void
mpz_div_r_2exp (mpz_t r, const mpz_t u, mp_bitcnt_t bit_index,
enum mpz_div_round_mode mode)
{
mp_size_t us, un, rn;
mp_ptr rp;
mp_limb_t mask;
us = u->_mp_size;
if (us == 0 || bit_index == 0)
{
r->_mp_size = 0;
return;
}
rn = (bit_index + GMP_LIMB_BITS - 1) / GMP_LIMB_BITS;
assert (rn > 0);
rp = MPZ_REALLOC (r, rn);
un = GMP_ABS (us);
mask = GMP_LIMB_MAX >> (rn * GMP_LIMB_BITS - bit_index);
if (rn > un)
{
/* Quotient (with truncation) is zero, and remainder is
non-zero */
if (mode == ((us > 0) ? GMP_DIV_CEIL : GMP_DIV_FLOOR)) /* us != 0 here. */
{
/* Have to negate and sign extend. */
mp_size_t i;
gmp_assert_nocarry (! mpn_neg (rp, u->_mp_d, un));
for (i = un; i < rn - 1; i++)
rp[i] = GMP_LIMB_MAX;
rp[rn-1] = mask;
us = -us;
}
else
{
/* Just copy */
if (r != u)
mpn_copyi (rp, u->_mp_d, un);
rn = un;
}
}
else
{
if (r != u)
mpn_copyi (rp, u->_mp_d, rn - 1);
rp[rn-1] = u->_mp_d[rn-1] & mask;
if (mode == ((us > 0) ? GMP_DIV_CEIL : GMP_DIV_FLOOR)) /* us != 0 here. */
{
/* If r != 0, compute 2^{bit_count} - r. */
mpn_neg (rp, rp, rn);
rp[rn-1] &= mask;
/* us is not used for anything else, so we can modify it
here to indicate flipped sign. */
us = -us;
}
}
rn = mpn_normalized_size (rp, rn);
r->_mp_size = us < 0 ? -rn : rn;
}
void
mpz_cdiv_q_2exp (mpz_t r, const mpz_t u, mp_bitcnt_t cnt)
{
mpz_div_q_2exp (r, u, cnt, GMP_DIV_CEIL);
}
void
mpz_fdiv_q_2exp (mpz_t r, const mpz_t u, mp_bitcnt_t cnt)
{
mpz_div_q_2exp (r, u, cnt, GMP_DIV_FLOOR);
}
void
mpz_tdiv_q_2exp (mpz_t r, const mpz_t u, mp_bitcnt_t cnt)
{
mpz_div_q_2exp (r, u, cnt, GMP_DIV_TRUNC);
}
void
mpz_cdiv_r_2exp (mpz_t r, const mpz_t u, mp_bitcnt_t cnt)
{
mpz_div_r_2exp (r, u, cnt, GMP_DIV_CEIL);
}
void
mpz_fdiv_r_2exp (mpz_t r, const mpz_t u, mp_bitcnt_t cnt)
{
mpz_div_r_2exp (r, u, cnt, GMP_DIV_FLOOR);
}
void
mpz_tdiv_r_2exp (mpz_t r, const mpz_t u, mp_bitcnt_t cnt)
{
mpz_div_r_2exp (r, u, cnt, GMP_DIV_TRUNC);
}
void
mpz_divexact (mpz_t q, const mpz_t n, const mpz_t d)
{
gmp_assert_nocarry (mpz_div_qr (q, NULL, n, d, GMP_DIV_TRUNC));
}
int
mpz_divisible_p (const mpz_t n, const mpz_t d)
{
return mpz_div_qr (NULL, NULL, n, d, GMP_DIV_TRUNC) == 0;
}
int
mpz_congruent_p (const mpz_t a, const mpz_t b, const mpz_t m)
{
mpz_t t;
int res;
/* a == b (mod 0) iff a == b */
if (mpz_sgn (m) == 0)
return (mpz_cmp (a, b) == 0);
mpz_init (t);
mpz_sub (t, a, b);
res = mpz_divisible_p (t, m);
mpz_clear (t);
return res;
}
static unsigned long
mpz_div_qr_ui (mpz_t q, mpz_t r,
const mpz_t n, unsigned long d, enum mpz_div_round_mode mode)
{
unsigned long ret;
mpz_t rr, dd;
mpz_init (rr);
mpz_init_set_ui (dd, d);
mpz_div_qr (q, rr, n, dd, mode);
mpz_clear (dd);
ret = mpz_get_ui (rr);
if (r)
mpz_swap (r, rr);
mpz_clear (rr);
return ret;
}
unsigned long
mpz_cdiv_qr_ui (mpz_t q, mpz_t r, const mpz_t n, unsigned long d)
{
return mpz_div_qr_ui (q, r, n, d, GMP_DIV_CEIL);
}
unsigned long
mpz_fdiv_qr_ui (mpz_t q, mpz_t r, const mpz_t n, unsigned long d)
{
return mpz_div_qr_ui (q, r, n, d, GMP_DIV_FLOOR);
}
unsigned long
mpz_tdiv_qr_ui (mpz_t q, mpz_t r, const mpz_t n, unsigned long d)
{
return mpz_div_qr_ui (q, r, n, d, GMP_DIV_TRUNC);
}
unsigned long
mpz_cdiv_q_ui (mpz_t q, const mpz_t n, unsigned long d)
{
return mpz_div_qr_ui (q, NULL, n, d, GMP_DIV_CEIL);
}
unsigned long
mpz_fdiv_q_ui (mpz_t q, const mpz_t n, unsigned long d)
{
return mpz_div_qr_ui (q, NULL, n, d, GMP_DIV_FLOOR);
}
unsigned long
mpz_tdiv_q_ui (mpz_t q, const mpz_t n, unsigned long d)
{
return mpz_div_qr_ui (q, NULL, n, d, GMP_DIV_TRUNC);
}
unsigned long
mpz_cdiv_r_ui (mpz_t r, const mpz_t n, unsigned long d)
{
return mpz_div_qr_ui (NULL, r, n, d, GMP_DIV_CEIL);
}
unsigned long
mpz_fdiv_r_ui (mpz_t r, const mpz_t n, unsigned long d)
{
return mpz_div_qr_ui (NULL, r, n, d, GMP_DIV_FLOOR);
}
unsigned long
mpz_tdiv_r_ui (mpz_t r, const mpz_t n, unsigned long d)
{
return mpz_div_qr_ui (NULL, r, n, d, GMP_DIV_TRUNC);
}
unsigned long
mpz_cdiv_ui (const mpz_t n, unsigned long d)
{
return mpz_div_qr_ui (NULL, NULL, n, d, GMP_DIV_CEIL);
}
unsigned long
mpz_fdiv_ui (const mpz_t n, unsigned long d)
{
return mpz_div_qr_ui (NULL, NULL, n, d, GMP_DIV_FLOOR);
}
unsigned long
mpz_tdiv_ui (const mpz_t n, unsigned long d)
{
return mpz_div_qr_ui (NULL, NULL, n, d, GMP_DIV_TRUNC);
}
unsigned long
mpz_mod_ui (mpz_t r, const mpz_t n, unsigned long d)
{
return mpz_div_qr_ui (NULL, r, n, d, GMP_DIV_FLOOR);
}
void
mpz_divexact_ui (mpz_t q, const mpz_t n, unsigned long d)
{
gmp_assert_nocarry (mpz_div_qr_ui (q, NULL, n, d, GMP_DIV_TRUNC));
}
int
mpz_divisible_ui_p (const mpz_t n, unsigned long d)
{
return mpz_div_qr_ui (NULL, NULL, n, d, GMP_DIV_TRUNC) == 0;
}
/* GCD */
static mp_limb_t
mpn_gcd_11 (mp_limb_t u, mp_limb_t v)
{
unsigned shift;
assert ( (u | v) > 0);
if (u == 0)
return v;
else if (v == 0)
return u;
gmp_ctz (shift, u | v);
u >>= shift;
v >>= shift;
if ( (u & 1) == 0)
MP_LIMB_T_SWAP (u, v);
while ( (v & 1) == 0)
v >>= 1;
while (u != v)
{
if (u > v)
{
u -= v;
do
u >>= 1;
while ( (u & 1) == 0);
}
else
{
v -= u;
do
v >>= 1;
while ( (v & 1) == 0);
}
}
return u << shift;
}
unsigned long
mpz_gcd_ui (mpz_t g, const mpz_t u, unsigned long v)
{
mpz_t t;
mpz_init_set_ui(t, v);
mpz_gcd (t, u, t);
if (v > 0)
v = mpz_get_ui (t);
if (g)
mpz_swap (t, g);
mpz_clear (t);
return v;
}
static mp_bitcnt_t
mpz_make_odd (mpz_t r)
{
mp_bitcnt_t shift;
assert (r->_mp_size > 0);
/* Count trailing zeros, equivalent to mpn_scan1, because we know that there is a 1 */
shift = mpn_scan1 (r->_mp_d, 0);
mpz_tdiv_q_2exp (r, r, shift);
return shift;
}
void
mpz_gcd (mpz_t g, const mpz_t u, const mpz_t v)
{
mpz_t tu, tv;
mp_bitcnt_t uz, vz, gz;
if (u->_mp_size == 0)
{
mpz_abs (g, v);
return;
}
if (v->_mp_size == 0)
{
mpz_abs (g, u);
return;
}
mpz_init (tu);
mpz_init (tv);
mpz_abs (tu, u);
uz = mpz_make_odd (tu);
mpz_abs (tv, v);
vz = mpz_make_odd (tv);
gz = GMP_MIN (uz, vz);
if (tu->_mp_size < tv->_mp_size)
mpz_swap (tu, tv);
mpz_tdiv_r (tu, tu, tv);
if (tu->_mp_size == 0)
{
mpz_swap (g, tv);
}
else
for (;;)
{
int c;
mpz_make_odd (tu);
c = mpz_cmp (tu, tv);
if (c == 0)
{
mpz_swap (g, tu);
break;
}
if (c < 0)
mpz_swap (tu, tv);
if (tv->_mp_size == 1)
{
mp_limb_t *gp;
mpz_tdiv_r (tu, tu, tv);
gp = MPZ_REALLOC (g, 1); /* gp = mpz_limbs_modify (g, 1); */
*gp = mpn_gcd_11 (tu->_mp_d[0], tv->_mp_d[0]);
g->_mp_size = *gp != 0; /* mpz_limbs_finish (g, 1); */
break;
}
mpz_sub (tu, tu, tv);
}
mpz_clear (tu);
mpz_clear (tv);
mpz_mul_2exp (g, g, gz);
}
void
mpz_gcdext (mpz_t g, mpz_t s, mpz_t t, const mpz_t u, const mpz_t v)
{
mpz_t tu, tv, s0, s1, t0, t1;
mp_bitcnt_t uz, vz, gz;
mp_bitcnt_t power;
if (u->_mp_size == 0)
{
/* g = 0 u + sgn(v) v */
signed long sign = mpz_sgn (v);
mpz_abs (g, v);
if (s)
s->_mp_size = 0;
if (t)
mpz_set_si (t, sign);
return;
}
if (v->_mp_size == 0)
{
/* g = sgn(u) u + 0 v */
signed long sign = mpz_sgn (u);
mpz_abs (g, u);
if (s)
mpz_set_si (s, sign);
if (t)
t->_mp_size = 0;
return;
}
mpz_init (tu);
mpz_init (tv);
mpz_init (s0);
mpz_init (s1);
mpz_init (t0);
mpz_init (t1);
mpz_abs (tu, u);
uz = mpz_make_odd (tu);
mpz_abs (tv, v);
vz = mpz_make_odd (tv);
gz = GMP_MIN (uz, vz);
uz -= gz;
vz -= gz;
/* Cofactors corresponding to odd gcd. gz handled later. */
if (tu->_mp_size < tv->_mp_size)
{
mpz_swap (tu, tv);
MPZ_SRCPTR_SWAP (u, v);
MPZ_PTR_SWAP (s, t);
MP_BITCNT_T_SWAP (uz, vz);
}
/* Maintain
*
* u = t0 tu + t1 tv
* v = s0 tu + s1 tv
*
* where u and v denote the inputs with common factors of two
* eliminated, and det (s0, t0; s1, t1) = 2^p. Then
*
* 2^p tu = s1 u - t1 v
* 2^p tv = -s0 u + t0 v
*/
/* After initial division, tu = q tv + tu', we have
*
* u = 2^uz (tu' + q tv)
* v = 2^vz tv
*
* or
*
* t0 = 2^uz, t1 = 2^uz q
* s0 = 0, s1 = 2^vz
*/
mpz_tdiv_qr (t1, tu, tu, tv);
mpz_mul_2exp (t1, t1, uz);
mpz_setbit (s1, vz);
power = uz + vz;
if (tu->_mp_size > 0)
{
mp_bitcnt_t shift;
shift = mpz_make_odd (tu);
mpz_setbit (t0, uz + shift);
power += shift;
for (;;)
{
int c;
c = mpz_cmp (tu, tv);
if (c == 0)
break;
if (c < 0)
{
/* tv = tv' + tu
*
* u = t0 tu + t1 (tv' + tu) = (t0 + t1) tu + t1 tv'
* v = s0 tu + s1 (tv' + tu) = (s0 + s1) tu + s1 tv' */
mpz_sub (tv, tv, tu);
mpz_add (t0, t0, t1);
mpz_add (s0, s0, s1);
shift = mpz_make_odd (tv);
mpz_mul_2exp (t1, t1, shift);
mpz_mul_2exp (s1, s1, shift);
}
else
{
mpz_sub (tu, tu, tv);
mpz_add (t1, t0, t1);
mpz_add (s1, s0, s1);
shift = mpz_make_odd (tu);
mpz_mul_2exp (t0, t0, shift);
mpz_mul_2exp (s0, s0, shift);
}
power += shift;
}
}
else
mpz_setbit (t0, uz);
/* Now tv = odd part of gcd, and -s0 and t0 are corresponding
cofactors. */
mpz_mul_2exp (tv, tv, gz);
mpz_neg (s0, s0);
/* 2^p g = s0 u + t0 v. Eliminate one factor of two at a time. To
adjust cofactors, we need u / g and v / g */
mpz_divexact (s1, v, tv);
mpz_abs (s1, s1);
mpz_divexact (t1, u, tv);
mpz_abs (t1, t1);
while (power-- > 0)
{
/* s0 u + t0 v = (s0 - v/g) u - (t0 + u/g) v */
if (mpz_odd_p (s0) || mpz_odd_p (t0))
{
mpz_sub (s0, s0, s1);
mpz_add (t0, t0, t1);
}
assert (mpz_even_p (t0) && mpz_even_p (s0));
mpz_tdiv_q_2exp (s0, s0, 1);
mpz_tdiv_q_2exp (t0, t0, 1);
}
/* Arrange so that |s| < |u| / 2g */
mpz_add (s1, s0, s1);
if (mpz_cmpabs (s0, s1) > 0)
{
mpz_swap (s0, s1);
mpz_sub (t0, t0, t1);
}
if (u->_mp_size < 0)
mpz_neg (s0, s0);
if (v->_mp_size < 0)
mpz_neg (t0, t0);
mpz_swap (g, tv);
if (s)
mpz_swap (s, s0);
if (t)
mpz_swap (t, t0);
mpz_clear (tu);
mpz_clear (tv);
mpz_clear (s0);
mpz_clear (s1);
mpz_clear (t0);
mpz_clear (t1);
}
void
mpz_lcm (mpz_t r, const mpz_t u, const mpz_t v)
{
mpz_t g;
if (u->_mp_size == 0 || v->_mp_size == 0)
{
r->_mp_size = 0;
return;
}
mpz_init (g);
mpz_gcd (g, u, v);
mpz_divexact (g, u, g);
mpz_mul (r, g, v);
mpz_clear (g);
mpz_abs (r, r);
}
void
mpz_lcm_ui (mpz_t r, const mpz_t u, unsigned long v)
{
if (v == 0 || u->_mp_size == 0)
{
r->_mp_size = 0;
return;
}
v /= mpz_gcd_ui (NULL, u, v);
mpz_mul_ui (r, u, v);
mpz_abs (r, r);
}
int
mpz_invert (mpz_t r, const mpz_t u, const mpz_t m)
{
mpz_t g, tr;
int invertible;
if (u->_mp_size == 0 || mpz_cmpabs_ui (m, 1) <= 0)
return 0;
mpz_init (g);
mpz_init (tr);
mpz_gcdext (g, tr, NULL, u, m);
invertible = (mpz_cmp_ui (g, 1) == 0);
if (invertible)
{
if (tr->_mp_size < 0)
{
if (m->_mp_size >= 0)
mpz_add (tr, tr, m);
else
mpz_sub (tr, tr, m);
}
mpz_swap (r, tr);
}
mpz_clear (g);
mpz_clear (tr);
return invertible;
}
/* Higher level operations (sqrt, pow and root) */
void
mpz_pow_ui (mpz_t r, const mpz_t b, unsigned long e)
{
unsigned long bit;
mpz_t tr;
mpz_init_set_ui (tr, 1);
bit = GMP_ULONG_HIGHBIT;
do
{
mpz_mul (tr, tr, tr);
if (e & bit)
mpz_mul (tr, tr, b);
bit >>= 1;
}
while (bit > 0);
mpz_swap (r, tr);
mpz_clear (tr);
}
void
mpz_ui_pow_ui (mpz_t r, unsigned long blimb, unsigned long e)
{
mpz_t b;
mpz_init_set_ui (b, blimb);
mpz_pow_ui (r, b, e);
mpz_clear (b);
}
void
mpz_powm (mpz_t r, const mpz_t b, const mpz_t e, const mpz_t m)
{
mpz_t tr;
mpz_t base;
mp_size_t en, mn;
mp_srcptr mp;
struct gmp_div_inverse minv;
unsigned shift;
mp_ptr tp = NULL;
en = GMP_ABS (e->_mp_size);
mn = GMP_ABS (m->_mp_size);
if (mn == 0)
gmp_die ("mpz_powm: Zero modulo.");
if (en == 0)
{
mpz_set_ui (r, mpz_cmpabs_ui (m, 1));
return;
}
mp = m->_mp_d;
mpn_div_qr_invert (&minv, mp, mn);
shift = minv.shift;
if (shift > 0)
{
/* To avoid shifts, we do all our reductions, except the final
one, using a *normalized* m. */
minv.shift = 0;
tp = gmp_alloc_limbs (mn);
gmp_assert_nocarry (mpn_lshift (tp, mp, mn, shift));
mp = tp;
}
mpz_init (base);
if (e->_mp_size < 0)
{
if (!mpz_invert (base, b, m))
gmp_die ("mpz_powm: Negative exponent and non-invertible base.");
}
else
{
mp_size_t bn;
mpz_abs (base, b);
bn = base->_mp_size;
if (bn >= mn)
{
mpn_div_qr_preinv (NULL, base->_mp_d, base->_mp_size, mp, mn, &minv);
bn = mn;
}
/* We have reduced the absolute value. Now take care of the
sign. Note that we get zero represented non-canonically as
m. */
if (b->_mp_size < 0)
{
mp_ptr bp = MPZ_REALLOC (base, mn);
gmp_assert_nocarry (mpn_sub (bp, mp, mn, bp, bn));
bn = mn;
}
base->_mp_size = mpn_normalized_size (base->_mp_d, bn);
}
mpz_init_set_ui (tr, 1);
while (--en >= 0)
{
mp_limb_t w = e->_mp_d[en];
mp_limb_t bit;
bit = GMP_LIMB_HIGHBIT;
do
{
mpz_mul (tr, tr, tr);
if (w & bit)
mpz_mul (tr, tr, base);
if (tr->_mp_size > mn)
{
mpn_div_qr_preinv (NULL, tr->_mp_d, tr->_mp_size, mp, mn, &minv);
tr->_mp_size = mpn_normalized_size (tr->_mp_d, mn);
}
bit >>= 1;
}
while (bit > 0);
}
/* Final reduction */
if (tr->_mp_size >= mn)
{
minv.shift = shift;
mpn_div_qr_preinv (NULL, tr->_mp_d, tr->_mp_size, mp, mn, &minv);
tr->_mp_size = mpn_normalized_size (tr->_mp_d, mn);
}
if (tp)
gmp_free_limbs (tp, mn);
mpz_swap (r, tr);
mpz_clear (tr);
mpz_clear (base);
}
void
mpz_powm_ui (mpz_t r, const mpz_t b, unsigned long elimb, const mpz_t m)
{
mpz_t e;
mpz_init_set_ui (e, elimb);
mpz_powm (r, b, e, m);
mpz_clear (e);
}
/* x=trunc(y^(1/z)), r=y-x^z */
void
mpz_rootrem (mpz_t x, mpz_t r, const mpz_t y, unsigned long z)
{
int sgn;
mp_bitcnt_t bc;
mpz_t t, u;
sgn = y->_mp_size < 0;
if ((~z & sgn) != 0)
gmp_die ("mpz_rootrem: Negative argument, with even root.");
if (z == 0)
gmp_die ("mpz_rootrem: Zeroth root.");
if (mpz_cmpabs_ui (y, 1) <= 0) {
if (x)
mpz_set (x, y);
if (r)
r->_mp_size = 0;
return;
}
mpz_init (u);
mpz_init (t);
bc = (mpz_sizeinbase (y, 2) - 1) / z + 1;
mpz_setbit (t, bc);
if (z == 2) /* simplify sqrt loop: z-1 == 1 */
do {
mpz_swap (u, t); /* u = x */
mpz_tdiv_q (t, y, u); /* t = y/x */
mpz_add (t, t, u); /* t = y/x + x */
mpz_tdiv_q_2exp (t, t, 1); /* x'= (y/x + x)/2 */
} while (mpz_cmpabs (t, u) < 0); /* |x'| < |x| */
else /* z != 2 */ {
mpz_t v;
mpz_init (v);
if (sgn)
mpz_neg (t, t);
do {
mpz_swap (u, t); /* u = x */
mpz_pow_ui (t, u, z - 1); /* t = x^(z-1) */
mpz_tdiv_q (t, y, t); /* t = y/x^(z-1) */
mpz_mul_ui (v, u, z - 1); /* v = x*(z-1) */
mpz_add (t, t, v); /* t = y/x^(z-1) + x*(z-1) */
mpz_tdiv_q_ui (t, t, z); /* x'=(y/x^(z-1) + x*(z-1))/z */
} while (mpz_cmpabs (t, u) < 0); /* |x'| < |x| */
mpz_clear (v);
}
if (r) {
mpz_pow_ui (t, u, z);
mpz_sub (r, y, t);
}
if (x)
mpz_swap (x, u);
mpz_clear (u);
mpz_clear (t);
}
int
mpz_root (mpz_t x, const mpz_t y, unsigned long z)
{
int res;
mpz_t r;
mpz_init (r);
mpz_rootrem (x, r, y, z);
res = r->_mp_size == 0;
mpz_clear (r);
return res;
}
/* Compute s = floor(sqrt(u)) and r = u - s^2. Allows r == NULL */
void
mpz_sqrtrem (mpz_t s, mpz_t r, const mpz_t u)
{
mpz_rootrem (s, r, u, 2);
}
void
mpz_sqrt (mpz_t s, const mpz_t u)
{
mpz_rootrem (s, NULL, u, 2);
}
int
mpz_perfect_square_p (const mpz_t u)
{
if (u->_mp_size <= 0)
return (u->_mp_size == 0);
else
return mpz_root (NULL, u, 2);
}
int
mpn_perfect_square_p (mp_srcptr p, mp_size_t n)
{
mpz_t t;
assert (n > 0);
assert (p [n-1] != 0);
return mpz_root (NULL, mpz_roinit_normal_n (t, p, n), 2);
}
mp_size_t
mpn_sqrtrem (mp_ptr sp, mp_ptr rp, mp_srcptr p, mp_size_t n)
{
mpz_t s, r, u;
mp_size_t res;
assert (n > 0);
assert (p [n-1] != 0);
mpz_init (r);
mpz_init (s);
mpz_rootrem (s, r, mpz_roinit_normal_n (u, p, n), 2);
assert (s->_mp_size == (n+1)/2);
mpn_copyd (sp, s->_mp_d, s->_mp_size);
mpz_clear (s);
res = r->_mp_size;
if (rp)
mpn_copyd (rp, r->_mp_d, res);
mpz_clear (r);
return res;
}
/* Combinatorics */
void
mpz_mfac_uiui (mpz_t x, unsigned long n, unsigned long m)
{
mpz_set_ui (x, n + (n == 0));
if (m + 1 < 2) return;
while (n > m + 1)
mpz_mul_ui (x, x, n -= m);
}
void
mpz_2fac_ui (mpz_t x, unsigned long n)
{
mpz_mfac_uiui (x, n, 2);
}
void
mpz_fac_ui (mpz_t x, unsigned long n)
{
mpz_mfac_uiui (x, n, 1);
}
void
mpz_bin_uiui (mpz_t r, unsigned long n, unsigned long k)
{
mpz_t t;
mpz_set_ui (r, k <= n);
if (k > (n >> 1))
k = (k <= n) ? n - k : 0;
mpz_init (t);
mpz_fac_ui (t, k);
for (; k > 0; --k)
mpz_mul_ui (r, r, n--);
mpz_divexact (r, r, t);
mpz_clear (t);
}
/* Primality testing */
/* Computes Kronecker (a/b) with odd b, a!=0 and GCD(a,b) = 1 */
/* Adapted from JACOBI_BASE_METHOD==4 in mpn/generic/jacbase.c */
static int
gmp_jacobi_coprime (mp_limb_t a, mp_limb_t b)
{
int c, bit = 0;
assert (b & 1);
assert (a != 0);
/* assert (mpn_gcd_11 (a, b) == 1); */
/* Below, we represent a and b shifted right so that the least
significant one bit is implicit. */
b >>= 1;
gmp_ctz(c, a);
a >>= 1;
for (;;)
{
a >>= c;
/* (2/b) = -1 if b = 3 or 5 mod 8 */
bit ^= c & (b ^ (b >> 1));
if (a < b)
{
if (a == 0)
return bit & 1 ? -1 : 1;
bit ^= a & b;
a = b - a;
b -= a;
}
else
{
a -= b;
assert (a != 0);
}
gmp_ctz(c, a);
++c;
}
}
static void
gmp_lucas_step_k_2k (mpz_t V, mpz_t Qk, const mpz_t n)
{
mpz_mod (Qk, Qk, n);
/* V_{2k} <- V_k ^ 2 - 2Q^k */
mpz_mul (V, V, V);
mpz_submul_ui (V, Qk, 2);
mpz_tdiv_r (V, V, n);
/* Q^{2k} = (Q^k)^2 */
mpz_mul (Qk, Qk, Qk);
}
/* Computes V_k, Q^k (mod n) for the Lucas' sequence */
/* with P=1, Q=Q; k = (n>>b0)|1. */
/* Requires an odd n > 4; b0 > 0; -2*Q must not overflow a long */
/* Returns (U_k == 0) and sets V=V_k and Qk=Q^k. */
static int
gmp_lucas_mod (mpz_t V, mpz_t Qk, long Q,
mp_bitcnt_t b0, const mpz_t n)
{
mp_bitcnt_t bs;
mpz_t U;
int res;
assert (b0 > 0);
assert (Q <= - (LONG_MIN / 2));
assert (Q >= - (LONG_MAX / 2));
assert (mpz_cmp_ui (n, 4) > 0);
assert (mpz_odd_p (n));
mpz_init_set_ui (U, 1); /* U1 = 1 */
mpz_set_ui (V, 1); /* V1 = 1 */
mpz_set_si (Qk, Q);
for (bs = mpz_sizeinbase (n, 2) - 1; --bs >= b0;)
{
/* U_{2k} <- U_k * V_k */
mpz_mul (U, U, V);
/* V_{2k} <- V_k ^ 2 - 2Q^k */
/* Q^{2k} = (Q^k)^2 */
gmp_lucas_step_k_2k (V, Qk, n);
/* A step k->k+1 is performed if the bit in $n$ is 1 */
/* mpz_tstbit(n,bs) or the bit is 0 in $n$ but */
/* should be 1 in $n+1$ (bs == b0) */
if (b0 == bs || mpz_tstbit (n, bs))
{
/* Q^{k+1} <- Q^k * Q */
mpz_mul_si (Qk, Qk, Q);
/* U_{k+1} <- (U_k + V_k) / 2 */
mpz_swap (U, V); /* Keep in V the old value of U_k */
mpz_add (U, U, V);
/* We have to compute U/2, so we need an even value, */
/* equivalent (mod n) */
if (mpz_odd_p (U))
mpz_add (U, U, n);
mpz_tdiv_q_2exp (U, U, 1);
/* V_{k+1} <-(D*U_k + V_k) / 2 =
U_{k+1} + (D-1)/2*U_k = U_{k+1} - 2Q*U_k */
mpz_mul_si (V, V, -2*Q);
mpz_add (V, U, V);
mpz_tdiv_r (V, V, n);
}
mpz_tdiv_r (U, U, n);
}
res = U->_mp_size == 0;
mpz_clear (U);
return res;
}
/* Performs strong Lucas' test on x, with parameters suggested */
/* for the BPSW test. Qk is only passed to recycle a variable. */
/* Requires GCD (x,6) = 1.*/
static int
gmp_stronglucas (const mpz_t x, mpz_t Qk)
{
mp_bitcnt_t b0;
mpz_t V, n;
mp_limb_t maxD, D; /* The absolute value is stored. */
long Q;
mp_limb_t tl;
/* Test on the absolute value. */
mpz_roinit_normal_n (n, x->_mp_d, GMP_ABS (x->_mp_size));
assert (mpz_odd_p (n));
/* assert (mpz_gcd_ui (NULL, n, 6) == 1); */
if (mpz_root (Qk, n, 2))
return 0; /* A square is composite. */
/* Check Ds up to square root (in case, n is prime)
or avoid overflows */
maxD = (Qk->_mp_size == 1) ? Qk->_mp_d [0] - 1 : GMP_LIMB_MAX;
D = 3;
/* Search a D such that (D/n) = -1 in the sequence 5,-7,9,-11,.. */
/* For those Ds we have (D/n) = (n/|D|) */
do
{
if (D >= maxD)
return 1 + (D != GMP_LIMB_MAX); /* (1 + ! ~ D) */
D += 2;
tl = mpz_tdiv_ui (n, D);
if (tl == 0)
return 0;
}
while (gmp_jacobi_coprime (tl, D) == 1);
mpz_init (V);
/* n-(D/n) = n+1 = d*2^{b0}, with d = (n>>b0) | 1 */
b0 = mpn_common_scan (~ n->_mp_d[0], 0, n->_mp_d, n->_mp_size, GMP_LIMB_MAX);
/* b0 = mpz_scan0 (n, 0); */
/* D= P^2 - 4Q; P = 1; Q = (1-D)/4 */
Q = (D & 2) ? (long) (D >> 2) + 1 : -(long) (D >> 2);
if (! gmp_lucas_mod (V, Qk, Q, b0, n)) /* If Ud != 0 */
while (V->_mp_size != 0 && --b0 != 0) /* while Vk != 0 */
/* V <- V ^ 2 - 2Q^k */
/* Q^{2k} = (Q^k)^2 */
gmp_lucas_step_k_2k (V, Qk, n);
mpz_clear (V);
return (b0 != 0);
}
static int
gmp_millerrabin (const mpz_t n, const mpz_t nm1, mpz_t y,
const mpz_t q, mp_bitcnt_t k)
{
assert (k > 0);
/* Caller must initialize y to the base. */
mpz_powm (y, y, q, n);
if (mpz_cmp_ui (y, 1) == 0 || mpz_cmp (y, nm1) == 0)
return 1;
while (--k > 0)
{
mpz_powm_ui (y, y, 2, n);
if (mpz_cmp (y, nm1) == 0)
return 1;
}
return 0;
}
/* This product is 0xc0cfd797, and fits in 32 bits. */
#define GMP_PRIME_PRODUCT \
(3UL*5UL*7UL*11UL*13UL*17UL*19UL*23UL*29UL)
/* Bit (p+1)/2 is set, for each odd prime <= 61 */
#define GMP_PRIME_MASK 0xc96996dcUL
int
mpz_probab_prime_p (const mpz_t n, int reps)
{
mpz_t nm1;
mpz_t q;
mpz_t y;
mp_bitcnt_t k;
int is_prime;
int j;
/* Note that we use the absolute value of n only, for compatibility
with the real GMP. */
if (mpz_even_p (n))
return (mpz_cmpabs_ui (n, 2) == 0) ? 2 : 0;
/* Above test excludes n == 0 */
assert (n->_mp_size != 0);
if (mpz_cmpabs_ui (n, 64) < 0)
return (GMP_PRIME_MASK >> (n->_mp_d[0] >> 1)) & 2;
if (mpz_gcd_ui (NULL, n, GMP_PRIME_PRODUCT) != 1)
return 0;
/* All prime factors are >= 31. */
if (mpz_cmpabs_ui (n, 31*31) < 0)
return 2;
mpz_init (nm1);
mpz_init (q);
/* Find q and k, where q is odd and n = 1 + 2**k * q. */
mpz_abs (nm1, n);
nm1->_mp_d[0] -= 1;
/* Count trailing zeros, equivalent to mpn_scan1, because we know that there is a 1 */
k = mpn_scan1 (nm1->_mp_d, 0);
mpz_tdiv_q_2exp (q, nm1, k);
/* BPSW test */
mpz_init_set_ui (y, 2);
is_prime = gmp_millerrabin (n, nm1, y, q, k) && gmp_stronglucas (n, y);
reps -= 24; /* skip the first 24 repetitions */
/* Use Miller-Rabin, with a deterministic sequence of bases, a[j] =
j^2 + j + 41 using Euler's polynomial. We potentially stop early,
if a[j] >= n - 1. Since n >= 31*31, this can happen only if reps >
30 (a[30] == 971 > 31*31 == 961). */
for (j = 0; is_prime & (j < reps); j++)
{
mpz_set_ui (y, (unsigned long) j*j+j+41);
if (mpz_cmp (y, nm1) >= 0)
{
/* Don't try any further bases. This "early" break does not affect
the result for any reasonable reps value (<=5000 was tested) */
assert (j >= 30);
break;
}
is_prime = gmp_millerrabin (n, nm1, y, q, k);
}
mpz_clear (nm1);
mpz_clear (q);
mpz_clear (y);
return is_prime;
}
/* Logical operations and bit manipulation. */
/* Numbers are treated as if represented in two's complement (and
infinitely sign extended). For a negative values we get the two's
complement from -x = ~x + 1, where ~ is bitwise complement.
Negation transforms
xxxx10...0
into
yyyy10...0
where yyyy is the bitwise complement of xxxx. So least significant
bits, up to and including the first one bit, are unchanged, and
the more significant bits are all complemented.
To change a bit from zero to one in a negative number, subtract the
corresponding power of two from the absolute value. This can never
underflow. To change a bit from one to zero, add the corresponding
power of two, and this might overflow. E.g., if x = -001111, the
two's complement is 110001. Clearing the least significant bit, we
get two's complement 110000, and -010000. */
int
mpz_tstbit (const mpz_t d, mp_bitcnt_t bit_index)
{
mp_size_t limb_index;
unsigned shift;
mp_size_t ds;
mp_size_t dn;
mp_limb_t w;
int bit;
ds = d->_mp_size;
dn = GMP_ABS (ds);
limb_index = bit_index / GMP_LIMB_BITS;
if (limb_index >= dn)
return ds < 0;
shift = bit_index % GMP_LIMB_BITS;
w = d->_mp_d[limb_index];
bit = (w >> shift) & 1;
if (ds < 0)
{
/* d < 0. Check if any of the bits below is set: If so, our bit
must be complemented. */
if (shift > 0 && (mp_limb_t) (w << (GMP_LIMB_BITS - shift)) > 0)
return bit ^ 1;
while (--limb_index >= 0)
if (d->_mp_d[limb_index] > 0)
return bit ^ 1;
}
return bit;
}
static void
mpz_abs_add_bit (mpz_t d, mp_bitcnt_t bit_index)
{
mp_size_t dn, limb_index;
mp_limb_t bit;
mp_ptr dp;
dn = GMP_ABS (d->_mp_size);
limb_index = bit_index / GMP_LIMB_BITS;
bit = (mp_limb_t) 1 << (bit_index % GMP_LIMB_BITS);
if (limb_index >= dn)
{
mp_size_t i;
/* The bit should be set outside of the end of the number.
We have to increase the size of the number. */
dp = MPZ_REALLOC (d, limb_index + 1);
dp[limb_index] = bit;
for (i = dn; i < limb_index; i++)
dp[i] = 0;
dn = limb_index + 1;
}
else
{
mp_limb_t cy;
dp = d->_mp_d;
cy = mpn_add_1 (dp + limb_index, dp + limb_index, dn - limb_index, bit);
if (cy > 0)
{
dp = MPZ_REALLOC (d, dn + 1);
dp[dn++] = cy;
}
}
d->_mp_size = (d->_mp_size < 0) ? - dn : dn;
}
static void
mpz_abs_sub_bit (mpz_t d, mp_bitcnt_t bit_index)
{
mp_size_t dn, limb_index;
mp_ptr dp;
mp_limb_t bit;
dn = GMP_ABS (d->_mp_size);
dp = d->_mp_d;
limb_index = bit_index / GMP_LIMB_BITS;
bit = (mp_limb_t) 1 << (bit_index % GMP_LIMB_BITS);
assert (limb_index < dn);
gmp_assert_nocarry (mpn_sub_1 (dp + limb_index, dp + limb_index,
dn - limb_index, bit));
dn = mpn_normalized_size (dp, dn);
d->_mp_size = (d->_mp_size < 0) ? - dn : dn;
}
void
mpz_setbit (mpz_t d, mp_bitcnt_t bit_index)
{
if (!mpz_tstbit (d, bit_index))
{
if (d->_mp_size >= 0)
mpz_abs_add_bit (d, bit_index);
else
mpz_abs_sub_bit (d, bit_index);
}
}
void
mpz_clrbit (mpz_t d, mp_bitcnt_t bit_index)
{
if (mpz_tstbit (d, bit_index))
{
if (d->_mp_size >= 0)
mpz_abs_sub_bit (d, bit_index);
else
mpz_abs_add_bit (d, bit_index);
}
}
void
mpz_combit (mpz_t d, mp_bitcnt_t bit_index)
{
if (mpz_tstbit (d, bit_index) ^ (d->_mp_size < 0))
mpz_abs_sub_bit (d, bit_index);
else
mpz_abs_add_bit (d, bit_index);
}
void
mpz_com (mpz_t r, const mpz_t u)
{
mpz_add_ui (r, u, 1);
mpz_neg (r, r);
}
void
mpz_and (mpz_t r, const mpz_t u, const mpz_t v)
{
mp_size_t un, vn, rn, i;
mp_ptr up, vp, rp;
mp_limb_t ux, vx, rx;
mp_limb_t uc, vc, rc;
mp_limb_t ul, vl, rl;
un = GMP_ABS (u->_mp_size);
vn = GMP_ABS (v->_mp_size);
if (un < vn)
{
MPZ_SRCPTR_SWAP (u, v);
MP_SIZE_T_SWAP (un, vn);
}
if (vn == 0)
{
r->_mp_size = 0;
return;
}
uc = u->_mp_size < 0;
vc = v->_mp_size < 0;
rc = uc & vc;
ux = -uc;
vx = -vc;
rx = -rc;
/* If the smaller input is positive, higher limbs don't matter. */
rn = vx ? un : vn;
rp = MPZ_REALLOC (r, rn + (mp_size_t) rc);
up = u->_mp_d;
vp = v->_mp_d;
i = 0;
do
{
ul = (up[i] ^ ux) + uc;
uc = ul < uc;
vl = (vp[i] ^ vx) + vc;
vc = vl < vc;
rl = ( (ul & vl) ^ rx) + rc;
rc = rl < rc;
rp[i] = rl;
}
while (++i < vn);
assert (vc == 0);
for (; i < rn; i++)
{
ul = (up[i] ^ ux) + uc;
uc = ul < uc;
rl = ( (ul & vx) ^ rx) + rc;
rc = rl < rc;
rp[i] = rl;
}
if (rc)
rp[rn++] = rc;
else
rn = mpn_normalized_size (rp, rn);
r->_mp_size = rx ? -rn : rn;
}
void
mpz_ior (mpz_t r, const mpz_t u, const mpz_t v)
{
mp_size_t un, vn, rn, i;
mp_ptr up, vp, rp;
mp_limb_t ux, vx, rx;
mp_limb_t uc, vc, rc;
mp_limb_t ul, vl, rl;
un = GMP_ABS (u->_mp_size);
vn = GMP_ABS (v->_mp_size);
if (un < vn)
{
MPZ_SRCPTR_SWAP (u, v);
MP_SIZE_T_SWAP (un, vn);
}
if (vn == 0)
{
mpz_set (r, u);
return;
}
uc = u->_mp_size < 0;
vc = v->_mp_size < 0;
rc = uc | vc;
ux = -uc;
vx = -vc;
rx = -rc;
/* If the smaller input is negative, by sign extension higher limbs
don't matter. */
rn = vx ? vn : un;
rp = MPZ_REALLOC (r, rn + (mp_size_t) rc);
up = u->_mp_d;
vp = v->_mp_d;
i = 0;
do
{
ul = (up[i] ^ ux) + uc;
uc = ul < uc;
vl = (vp[i] ^ vx) + vc;
vc = vl < vc;
rl = ( (ul | vl) ^ rx) + rc;
rc = rl < rc;
rp[i] = rl;
}
while (++i < vn);
assert (vc == 0);
for (; i < rn; i++)
{
ul = (up[i] ^ ux) + uc;
uc = ul < uc;
rl = ( (ul | vx) ^ rx) + rc;
rc = rl < rc;
rp[i] = rl;
}
if (rc)
rp[rn++] = rc;
else
rn = mpn_normalized_size (rp, rn);
r->_mp_size = rx ? -rn : rn;
}
void
mpz_xor (mpz_t r, const mpz_t u, const mpz_t v)
{
mp_size_t un, vn, i;
mp_ptr up, vp, rp;
mp_limb_t ux, vx, rx;
mp_limb_t uc, vc, rc;
mp_limb_t ul, vl, rl;
un = GMP_ABS (u->_mp_size);
vn = GMP_ABS (v->_mp_size);
if (un < vn)
{
MPZ_SRCPTR_SWAP (u, v);
MP_SIZE_T_SWAP (un, vn);
}
if (vn == 0)
{
mpz_set (r, u);
return;
}
uc = u->_mp_size < 0;
vc = v->_mp_size < 0;
rc = uc ^ vc;
ux = -uc;
vx = -vc;
rx = -rc;
rp = MPZ_REALLOC (r, un + (mp_size_t) rc);
up = u->_mp_d;
vp = v->_mp_d;
i = 0;
do
{
ul = (up[i] ^ ux) + uc;
uc = ul < uc;
vl = (vp[i] ^ vx) + vc;
vc = vl < vc;
rl = (ul ^ vl ^ rx) + rc;
rc = rl < rc;
rp[i] = rl;
}
while (++i < vn);
assert (vc == 0);
for (; i < un; i++)
{
ul = (up[i] ^ ux) + uc;
uc = ul < uc;
rl = (ul ^ ux) + rc;
rc = rl < rc;
rp[i] = rl;
}
if (rc)
rp[un++] = rc;
else
un = mpn_normalized_size (rp, un);
r->_mp_size = rx ? -un : un;
}
static unsigned
gmp_popcount_limb (mp_limb_t x)
{
unsigned c;
/* Do 16 bits at a time, to avoid limb-sized constants. */
int LOCAL_SHIFT_BITS = 16;
for (c = 0; x > 0;)
{
unsigned w = x - ((x >> 1) & 0x5555);
w = ((w >> 2) & 0x3333) + (w & 0x3333);
w = (w >> 4) + w;
w = ((w >> 8) & 0x000f) + (w & 0x000f);
c += w;
if (GMP_LIMB_BITS > LOCAL_SHIFT_BITS)
x >>= LOCAL_SHIFT_BITS;
else
x = 0;
}
return c;
}
mp_bitcnt_t
mpn_popcount (mp_srcptr p, mp_size_t n)
{
mp_size_t i;
mp_bitcnt_t c;
for (c = 0, i = 0; i < n; i++)
c += gmp_popcount_limb (p[i]);
return c;
}
mp_bitcnt_t
mpz_popcount (const mpz_t u)
{
mp_size_t un;
un = u->_mp_size;
if (un < 0)
return ~(mp_bitcnt_t) 0;
return mpn_popcount (u->_mp_d, un);
}
mp_bitcnt_t
mpz_hamdist (const mpz_t u, const mpz_t v)
{
mp_size_t un, vn, i;
mp_limb_t uc, vc, ul, vl, comp;
mp_srcptr up, vp;
mp_bitcnt_t c;
un = u->_mp_size;
vn = v->_mp_size;
if ( (un ^ vn) < 0)
return ~(mp_bitcnt_t) 0;
comp = - (uc = vc = (un < 0));
if (uc)
{
assert (vn < 0);
un = -un;
vn = -vn;
}
up = u->_mp_d;
vp = v->_mp_d;
if (un < vn)
MPN_SRCPTR_SWAP (up, un, vp, vn);
for (i = 0, c = 0; i < vn; i++)
{
ul = (up[i] ^ comp) + uc;
uc = ul < uc;
vl = (vp[i] ^ comp) + vc;
vc = vl < vc;
c += gmp_popcount_limb (ul ^ vl);
}
assert (vc == 0);
for (; i < un; i++)
{
ul = (up[i] ^ comp) + uc;
uc = ul < uc;
c += gmp_popcount_limb (ul ^ comp);
}
return c;
}
mp_bitcnt_t
mpz_scan1 (const mpz_t u, mp_bitcnt_t starting_bit)
{
mp_ptr up;
mp_size_t us, un, i;
mp_limb_t limb, ux;
us = u->_mp_size;
un = GMP_ABS (us);
i = starting_bit / GMP_LIMB_BITS;
/* Past the end there's no 1 bits for u>=0, or an immediate 1 bit
for u<0. Notice this test picks up any u==0 too. */
if (i >= un)
return (us >= 0 ? ~(mp_bitcnt_t) 0 : starting_bit);
up = u->_mp_d;
ux = 0;
limb = up[i];
if (starting_bit != 0)
{
if (us < 0)
{
ux = mpn_zero_p (up, i);
limb = ~ limb + ux;
ux = - (mp_limb_t) (limb >= ux);
}
/* Mask to 0 all bits before starting_bit, thus ignoring them. */
limb &= GMP_LIMB_MAX << (starting_bit % GMP_LIMB_BITS);
}
return mpn_common_scan (limb, i, up, un, ux);
}
mp_bitcnt_t
mpz_scan0 (const mpz_t u, mp_bitcnt_t starting_bit)
{
mp_ptr up;
mp_size_t us, un, i;
mp_limb_t limb, ux;
us = u->_mp_size;
ux = - (mp_limb_t) (us >= 0);
un = GMP_ABS (us);
i = starting_bit / GMP_LIMB_BITS;
/* When past end, there's an immediate 0 bit for u>=0, or no 0 bits for
u<0. Notice this test picks up all cases of u==0 too. */
if (i >= un)
return (ux ? starting_bit : ~(mp_bitcnt_t) 0);
up = u->_mp_d;
limb = up[i] ^ ux;
if (ux == 0)
limb -= mpn_zero_p (up, i); /* limb = ~(~limb + zero_p) */
/* Mask all bits before starting_bit, thus ignoring them. */
limb &= GMP_LIMB_MAX << (starting_bit % GMP_LIMB_BITS);
return mpn_common_scan (limb, i, up, un, ux);
}
/* MPZ base conversion. */
size_t
mpz_sizeinbase (const mpz_t u, int base)
{
mp_size_t un, tn;
mp_srcptr up;
mp_ptr tp;
mp_bitcnt_t bits;
struct gmp_div_inverse bi;
size_t ndigits;
assert (base >= 2);
assert (base <= 62);
un = GMP_ABS (u->_mp_size);
if (un == 0)
return 1;
up = u->_mp_d;
bits = (un - 1) * GMP_LIMB_BITS + mpn_limb_size_in_base_2 (up[un-1]);
switch (base)
{
case 2:
return bits;
case 4:
return (bits + 1) / 2;
case 8:
return (bits + 2) / 3;
case 16:
return (bits + 3) / 4;
case 32:
return (bits + 4) / 5;
/* FIXME: Do something more clever for the common case of base
10. */
}
tp = gmp_alloc_limbs (un);
mpn_copyi (tp, up, un);
mpn_div_qr_1_invert (&bi, base);
tn = un;
ndigits = 0;
do
{
ndigits++;
mpn_div_qr_1_preinv (tp, tp, tn, &bi);
tn -= (tp[tn-1] == 0);
}
while (tn > 0);
gmp_free_limbs (tp, un);
return ndigits;
}
char *
mpz_get_str (char *sp, int base, const mpz_t u)
{
unsigned bits;
const char *digits;
mp_size_t un;
size_t i, sn, osn;
digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
if (base > 1)
{
if (base <= 36)
digits = "0123456789abcdefghijklmnopqrstuvwxyz";
else if (base > 62)
return NULL;
}
else if (base >= -1)
base = 10;
else
{
base = -base;
if (base > 36)
return NULL;
}
sn = 1 + mpz_sizeinbase (u, base);
if (!sp)
{
osn = 1 + sn;
sp = (char *) gmp_alloc (osn);
}
else
osn = 0;
un = GMP_ABS (u->_mp_size);
if (un == 0)
{
sp[0] = '0';
sn = 1;
goto ret;
}
i = 0;
if (u->_mp_size < 0)
sp[i++] = '-';
bits = mpn_base_power_of_two_p (base);
if (bits)
/* Not modified in this case. */
sn = i + mpn_get_str_bits ((unsigned char *) sp + i, bits, u->_mp_d, un);
else
{
struct mpn_base_info info;
mp_ptr tp;
mpn_get_base_info (&info, base);
tp = gmp_alloc_limbs (un);
mpn_copyi (tp, u->_mp_d, un);
sn = i + mpn_get_str_other ((unsigned char *) sp + i, base, &info, tp, un);
gmp_free_limbs (tp, un);
}
for (; i < sn; i++)
sp[i] = digits[(unsigned char) sp[i]];
ret:
sp[sn] = '\0';
if (osn && osn != sn + 1)
sp = (char*) gmp_realloc (sp, osn, sn + 1);
return sp;
}
int
mpz_set_str (mpz_t r, const char *sp, int base)
{
unsigned bits, value_of_a;
mp_size_t rn, alloc;
mp_ptr rp;
size_t dn, sn;
int sign;
unsigned char *dp;
assert (base == 0 || (base >= 2 && base <= 62));
while (isspace( (unsigned char) *sp))
sp++;
sign = (*sp == '-');
sp += sign;
if (base == 0)
{
if (sp[0] == '0')
{
if (sp[1] == 'x' || sp[1] == 'X')
{
base = 16;
sp += 2;
}
else if (sp[1] == 'b' || sp[1] == 'B')
{
base = 2;
sp += 2;
}
else
base = 8;
}
else
base = 10;
}
if (!*sp)
{
r->_mp_size = 0;
return -1;
}
sn = strlen(sp);
dp = (unsigned char *) gmp_alloc (sn);
value_of_a = (base > 36) ? 36 : 10;
for (dn = 0; *sp; sp++)
{
unsigned digit;
if (isspace ((unsigned char) *sp))
continue;
else if (*sp >= '0' && *sp <= '9')
digit = *sp - '0';
else if (*sp >= 'a' && *sp <= 'z')
digit = *sp - 'a' + value_of_a;
else if (*sp >= 'A' && *sp <= 'Z')
digit = *sp - 'A' + 10;
else
digit = base; /* fail */
if (digit >= (unsigned) base)
{
gmp_free (dp, sn);
r->_mp_size = 0;
return -1;
}
dp[dn++] = digit;
}
if (!dn)
{
gmp_free (dp, sn);
r->_mp_size = 0;
return -1;
}
bits = mpn_base_power_of_two_p (base);
if (bits > 0)
{
alloc = (dn * bits + GMP_LIMB_BITS - 1) / GMP_LIMB_BITS;
rp = MPZ_REALLOC (r, alloc);
rn = mpn_set_str_bits (rp, dp, dn, bits);
}
else
{
struct mpn_base_info info;
mpn_get_base_info (&info, base);
alloc = (dn + info.exp - 1) / info.exp;
rp = MPZ_REALLOC (r, alloc);
rn = mpn_set_str_other (rp, dp, dn, base, &info);
/* Normalization, needed for all-zero input. */
assert (rn > 0);
rn -= rp[rn-1] == 0;
}
assert (rn <= alloc);
gmp_free (dp, sn);
r->_mp_size = sign ? - rn : rn;
return 0;
}
int
mpz_init_set_str (mpz_t r, const char *sp, int base)
{
mpz_init (r);
return mpz_set_str (r, sp, base);
}
size_t
mpz_out_str (FILE *stream, int base, const mpz_t x)
{
char *str;
size_t len, n;
str = mpz_get_str (NULL, base, x);
if (!str)
return 0;
len = strlen (str);
n = fwrite (str, 1, len, stream);
gmp_free (str, len + 1);
return n;
}
static int
gmp_detect_endian (void)
{
static const int i = 2;
const unsigned char *p = (const unsigned char *) &i;
return 1 - *p;
}
/* Import and export. Does not support nails. */
void
mpz_import (mpz_t r, size_t count, int order, size_t size, int endian,
size_t nails, const void *src)
{
const unsigned char *p;
ptrdiff_t word_step;
mp_ptr rp;
mp_size_t rn;
/* The current (partial) limb. */
mp_limb_t limb;
/* The number of bytes already copied to this limb (starting from
the low end). */
size_t bytes;
/* The index where the limb should be stored, when completed. */
mp_size_t i;
if (nails != 0)
gmp_die ("mpz_import: Nails not supported.");
assert (order == 1 || order == -1);
assert (endian >= -1 && endian <= 1);
if (endian == 0)
endian = gmp_detect_endian ();
p = (unsigned char *) src;
word_step = (order != endian) ? 2 * size : 0;
/* Process bytes from the least significant end, so point p at the
least significant word. */
if (order == 1)
{
p += size * (count - 1);
word_step = - word_step;
}
/* And at least significant byte of that word. */
if (endian == 1)
p += (size - 1);
rn = (size * count + sizeof(mp_limb_t) - 1) / sizeof(mp_limb_t);
rp = MPZ_REALLOC (r, rn);
for (limb = 0, bytes = 0, i = 0; count > 0; count--, p += word_step)
{
size_t j;
for (j = 0; j < size; j++, p -= (ptrdiff_t) endian)
{
limb |= (mp_limb_t) *p << (bytes++ * CHAR_BIT);
if (bytes == sizeof(mp_limb_t))
{
rp[i++] = limb;
bytes = 0;
limb = 0;
}
}
}
assert (i + (bytes > 0) == rn);
if (limb != 0)
rp[i++] = limb;
else
i = mpn_normalized_size (rp, i);
r->_mp_size = i;
}
void *
mpz_export (void *r, size_t *countp, int order, size_t size, int endian,
size_t nails, const mpz_t u)
{
size_t count;
mp_size_t un;
if (nails != 0)
gmp_die ("mpz_export: Nails not supported.");
assert (order == 1 || order == -1);
assert (endian >= -1 && endian <= 1);
assert (size > 0 || u->_mp_size == 0);
un = u->_mp_size;
count = 0;
if (un != 0)
{
size_t k;
unsigned char *p;
ptrdiff_t word_step;
/* The current (partial) limb. */
mp_limb_t limb;
/* The number of bytes left to do in this limb. */
size_t bytes;
/* The index where the limb was read. */
mp_size_t i;
un = GMP_ABS (un);
/* Count bytes in top limb. */
limb = u->_mp_d[un-1];
assert (limb != 0);
k = (GMP_LIMB_BITS <= CHAR_BIT);
if (!k)
{
do {
int LOCAL_CHAR_BIT = CHAR_BIT;
k++; limb >>= LOCAL_CHAR_BIT;
} while (limb != 0);
}
/* else limb = 0; */
count = (k + (un-1) * sizeof (mp_limb_t) + size - 1) / size;
if (!r)
r = gmp_alloc (count * size);
if (endian == 0)
endian = gmp_detect_endian ();
p = (unsigned char *) r;
word_step = (order != endian) ? 2 * size : 0;
/* Process bytes from the least significant end, so point p at the
least significant word. */
if (order == 1)
{
p += size * (count - 1);
word_step = - word_step;
}
/* And at least significant byte of that word. */
if (endian == 1)
p += (size - 1);
for (bytes = 0, i = 0, k = 0; k < count; k++, p += word_step)
{
size_t j;
for (j = 0; j < size; ++j, p -= (ptrdiff_t) endian)
{
if (sizeof (mp_limb_t) == 1)
{
if (i < un)
*p = u->_mp_d[i++];
else
*p = 0;
}
else
{
int LOCAL_CHAR_BIT = CHAR_BIT;
if (bytes == 0)
{
if (i < un)
limb = u->_mp_d[i++];
bytes = sizeof (mp_limb_t);
}
*p = limb;
limb >>= LOCAL_CHAR_BIT;
bytes--;
}
}
}
assert (i == un);
assert (k == count);
}
if (countp)
*countp = count;
return r;
}
#include <cstdio>
#include <iostream>
#include "testlib.h"
int main(int argc, char** argv) {
registerTestlibCmd(argc, argv);
registerGen(argc, argv, 1);
int n = inf.readInt();
int q = inf.readInt();
int rangel = inf.readInt();
int ranger = inf.readInt();
printf("%d %d\n", n, q);
auto arr = new long[n + 1]();
for (int i = 1; i <= n; i++)
{
arr[i] = rnd.next(rangel, ranger);
printf("%ld ", arr[i]);
arr[i] += arr[i - 1];
}
printf("\n");
auto l = new int[q], r = new int[q];
long ans = 0;
for (int i = 0; i < q; i++)
{
l[i] = rnd.next(1, n);
r[i] = rnd.next(1, n);
if (l[i] > r[i])
std::swap(l[i], r[i]);
printf("%d %d\n", l[i], r[i]);
ans ^= arr[r[i]] - arr[l[i] - 1];
}
fflush(stdout);
delete[] l;
delete[] r;
delete[] arr;
if (ans == ouf.readLong())
quitf(_ok, "The answer is %ld.", ans);
quitf(_wa, "Wrong answer.");
}
#include <ctime>
#include <fstream>
#include <random>
#include <string>
#include <vector>
int main() {
using namespace std;
random_device seed;
mt19937 rnd(seed());
uniform_int_distribution<long> nm_dist(1, 100000);
uniform_real_distribution<double> qu_dist(0, 1);
uniform_int_distribution<long> numtyp_dist(0, 3);
uniform_int_distribution<long> qnum_dist(1, 1000000000);
double query = 0.0;
for (int t = 1; t < 25; t++, query += 0.04)
{
ofstream iout("./data/random" + to_string(t) + ".in");
ofstream oout("./data/random" + to_string(t) + ".out");
int64_t n = nm_dist(rnd), m = nm_dist(rnd);
uniform_int_distribution<int64_t> lr_dist(1, n);
uniform_int_distribution<int64_t> sk_dist(1, max<int>(log2(n), 1));
uniform_real_distribution<double> num_dist(0, 1);
uniform_int_distribution<int64_t> hi_dist(max<int>(log2(n), 1), n);
uniform_int_distribution<int64_t> norm_dist(1, n);
long numtyp = numtyp_dist(rnd);
iout << n << ' ' << m << endl;
vector<long> arr(n + 1, 0);
while (m--)
{
if (qu_dist(rnd) < query)
{
long a, b = qnum_dist(rnd);
switch (numtyp)
{
case 0:
a = sk_dist(rnd);
break;
case 1:
a = pow(n, num_dist(rnd));
break;
case 2:
a = norm_dist(rnd);
default:
a = hi_dist(rnd);
break;
}
iout << 1 << ' ' << a << ' ' << b << endl;
for (int i = 1; i * a <= n; i++)
arr[i * a] += b;
}
else
{
long a = lr_dist(rnd), b = lr_dist(rnd);
if (a > b)
swap(a, b);
iout << 2 << ' ' << a << ' ' << b << endl;
long res = 0;
for (long i = a; i <= b; i++)
res += arr[i];
oout << res << endl;
}
}
}
return 0;
}
#include <iostream>
#include <vector>
#include <stack>
#include <cmath>
#include <algorithm>
using namespace std;
const int MAXN = 1000000;
const int MAXT = 2 * MAXN;
int n, m, Q;
vector<int> G[MAXN + 5];
vector<int> T[MAXT + 5];
int dfn[MAXN + 5], low[MAXN + 5];
int stk[MAXN + 5], top;
int idx, bcc_cnt;
int comp[MAXT + 5];
int depth[MAXT + 5], sum[MAXT + 5];
int fa[MAXT + 5][21];
int LOG;
void tarjan(int u) {
dfn[u] = low[u] = ++idx;
stk[++top] = u;
for (int tmp = 0; tmp < G[u].size(); tmp++) {
int v = G[u][tmp];
if (!dfn[v]) {
tarjan(v);
low[u] = min(low[u], low[v]);
if (low[v] >= dfn[u]) {
bcc_cnt++;
int w;
do {
w = stk[top--];
T[bcc_cnt + n].push_back(w);
T[w].push_back(bcc_cnt + n);
} while (w != v);
T[bcc_cnt + n].push_back(u);
T[u].push_back(bcc_cnt + n);
}
} else {
low[u] = min(low[u], dfn[v]);
}
}
}
void dfs(int u, int father, int comp_id) {
comp[u] = comp_id;
depth[u] = depth[father] + 1;
sum[u] = sum[father] + (u <= n ? 1 : 0);
fa[u][0] = father;
for (int i = 1; i <= LOG; i++) {
fa[u][i] = fa[fa[u][i - 1]][i - 1];
}
for (int tmp = 0; tmp < T[u].size(); tmp++) {
int v = T[u][tmp];
if (v == father) continue;
dfs(v, u, comp_id);
}
}
int lca(int u, int v) {
if (depth[u] < depth[v]) swap(u, v);
for (int i = LOG; i >= 0; i--) {
if (depth[fa[u][i]] >= depth[v]) {
u = fa[u][i];
}
}
if (u == v) return u;
for (int i = LOG; i >= 0; i--) {
if (fa[u][i] != fa[v][i]) {
u = fa[u][i];
v = fa[v][i];
}
}
return fa[u][0];
}
int main() {
scanf("%d%d%d", &n, &m, &Q);
for (int i = 1; i <= m; i++) {
int u, v;
scanf("%d%d", &u, &v);
G[u].push_back(v);
G[v].push_back(u);
}
idx = 0;
top = 0;
bcc_cnt = 0;
for (int i = 1; i <= n; i++) {
if (!dfn[i]) {
tarjan(i);
if (top > 0) {
top--;
}
}
}
LOG = ceil(log2(n + bcc_cnt));
for (int i = 1; i <= n; i++) {
if (comp[i] == 0) {
dfs(i, 0, i);
}
}
while (Q--) {
int S, T;
scanf("%d%d", &S, &T);
if (S == T) {
printf("0\n");
} else if (comp[S] != comp[T]) {
printf("%d\n", n - 2);
} else {
int L = lca(S, T);
int total = sum[S] + sum[T] - 2 * sum[L] + (L <= n ? 1 : 0);
printf("%d\n", total - 2);
}
}
return 0;
}
#include "testlib.h"
#include <set>
int main(void) {
using namespace std;
registerValidation();
int n, m, q;
n = inf.readInt(1, 100000, "N");
inf.readSpace();
m = inf.readInt(1, 100000, "M");
inf.readSpace();
q = inf.readInt(1, 100000, "Q");
inf.readEoln();
set<pair<int, int> > visit;
while(m--)
{
int u, v;
u = inf.readInt(1, n, "u");
v = inf.readInt(1, n, "v");
ensuref(u != v, "u == v");
if(u > v)
swap(u, v);
ensuref(visit.find(make_pair(u, v)) == visit.end(), "found {u, v}");
visit.insert(make_pair(u, v));
inf.readEoln();
}
while(q--)
{
int s, t;
s = inf.readInt(1, n, "S");
t = inf.readInt(1, n, "T");
ensuref(s != t, "S == T");
inf.readEoln();
}
inf.readEof();
return 0;
}
给定一个无向图,多次询问,每次询问给出两个点 $S$ 和 $T$,求有多少个点 $v$($v \neq S$ 且 $v \neq T$)满足删除 $v$ 后 $S$ 和 $T$ 不再连通。
本问题的核心在于找出图中所有能够断开 $S$ 和 $T$ 的连接的点,即 $S$ 和 $T$ 之间的必经点。为了解决这个问题,我们使用圆方树(Block-Cut Tree)来高效地识别这些必经点。
点双连通分量(BCC)识别:
圆方树构建:
连通性判断:
必经点计算:
时间复杂度:
空间复杂度:
#include <iostream>
#include <vector>
#include <stack>
#include <cmath>
#include <algorithm>
using namespace std;
const int MAXN = 1000000;
const int MAXT = 2 * MAXN;
int n, m, Q;
vector<int> G[MAXN + 5];
vector<int> T[MAXT + 5];
int dfn[MAXN + 5], low[MAXN + 5];
int stk[MAXN + 5], top;
int idx, bcc_cnt;
int comp[MAXT + 5];
int depth[MAXT + 5], sum[MAXT + 5];
int fa[MAXT + 5][21];
int LOG;
void tarjan(int u) {
dfn[u] = low[u] = ++idx;
stk[++top] = u;
for (int v : G[u]) {
if (!dfn[v]) {
tarjan(v);
low[u] = min(low[u], low[v]);
if (low[v] >= dfn[u]) {
bcc_cnt++;
int w;
do {
w = stk[top--];
T[bcc_cnt + n].push_back(w);
T[w].push_back(bcc_cnt + n);
} while (w != v);
T[bcc_cnt + n].push_back(u);
T[u].push_back(bcc_cnt + n);
}
} else {
low[u] = min(low[u], dfn[v]);
}
}
}
void dfs(int u, int father, int comp_id) {
comp[u] = comp_id;
depth[u] = depth[father] + 1;
sum[u] = sum[father] + (u <= n ? 1 : 0);
fa[u][0] = father;
for (int i = 1; i <= LOG; i++) {
fa[u][i] = fa[fa[u][i - 1]][i - 1];
}
for (int v : T[u]) {
if (v == father) continue;
dfs(v, u, comp_id);
}
}
int lca(int u, int v) {
if (depth[u] < depth[v]) swap(u, v);
for (int i = LOG; i >= 0; i--) {
if (depth[fa[u][i]] >= depth[v]) {
u = fa[u][i];
}
}
if (u == v) return u;
for (int i = LOG; i >= 0; i--) {
if (fa[u][i] != fa[v][i]) {
u = fa[u][i];
v = fa[v][i];
}
}
return fa[u][0];
}
int main() {
scanf("%d%d%d", &n, &m, &Q);
for (int i = 1; i <= m; i++) {
int u, v;
scanf("%d%d", &u, &v);
G[u].push_back(v);
G[v].push_back(u);
}
idx = 0;
top = 0;
bcc_cnt = 0;
for (int i = 1; i <= n; i++) {
if (!dfn[i]) {
tarjan(i);
}
}
LOG = ceil(log2(n + bcc_cnt));
for (int i = 1; i <= n; i++) {
if (comp[i] == 0) {
dfs(i, 0, i);
}
}
while (Q--) {
int S, T;
scanf("%d%d", &S, &T);
if (S == T) {
printf("0\n");
} else if (comp[S] != comp[T]) {
printf("%d\n", n - 2);
} else {
int L = lca(S, T);
int total = sum[S] + sum[T] - 2 * sum[L] + (L <= n ? 1 : 0);
printf("%d\n", total - 2);
}
}
return 0;
}
本题解通过构建圆方树和利用 LCA 技术,高效地解决了图中必经点查询问题。算法正确性基于圆方树的性质,能够快速计算任意两点之间的必经点数量,适用于大规模数据输入。
请谨慎阅读(尤其当lxn靠近时)
https://www.luogu.com.cn/article/k8nh9vo0
看了漫士的这期视频,我忽然发现,std::sort 竟是
$\Theta(N \log N)$ 的,便马上做了个实验,Amazing啊,竟然有点符合本福特定律,以下是实验数据:
Avg_N = 5.06609e+06, Avg_time = 0.230004 s
P[1] = 0.229492
P[2] = 0.246826
P[3] = 0.234131
P[4] = 0.168091
P[5] = 0.0266113
P[6] = 0.0234375
P[7] = 0.0255127
P[8] = 0.0220947
P[9] = 0.0238037
也有可能是随机的数据有问题?希望知道的给一个答复。
代码(g++-14 main.cpp -o main -O2 -march=native):https://www.luogu.com.cn/paste/bilcktnw
main.cpp
#include <algorithm>
#include <ctime>
#include <iostream>
#include <numeric>
#include <random>
constexpr unsigned Tests = 8192;
clock_t run(unsigned n, unsigned* arr) {
auto start = clock();
std::sort(arr, arr + n);
return clock() - start;
}
int main() {
using namespace std;
unsigned long cnt[10]{};
double nsum = 0, tsum = 0;
default_random_engine rnd(time(nullptr));
uniform_int_distribution ndis(10000, 9999999);
for (int i = 0; i < Tests; i++)
{
int n = ndis(rnd);
nsum += n;
cout << "Running Test " << i << ", N = " << n << "\n";
auto arr = new unsigned[n];
for (int j = 0; j < n; j++)
arr[j] = rnd();
auto res = run(n, arr);
tsum += static_cast<double>(res) / CLOCKS_PER_SEC;
while (res > 9)
res /= 10;
++cnt[res];
delete[] arr;
}
unsigned long tot = accumulate(cnt + 1, cnt + 10, 0ul);
cout << "Avg_N = " << nsum / Tests << ", Avg_time = " << tsum / Tests << " s\n";
for (int i = 1; i < 10; i++)
cout << "P[" << i << "] = "
<< static_cast<double>(cnt[i]) / tot << endl;
return 0;
}
如题,已知一棵包含 $N$ 个结点的树(连通且无环),每个节点上包含一个数值,需要支持以下操作:
1 x y z,表示将树从 $x$ 到 $y$ 结点最短路径上所有节点的值都加上 $z$。
2 x y,表示求树从 $x$ 到 $y$ 结点最短路径上所有节点的值之和。
3 x z,表示将以 $x$ 为根节点的子树内所有节点值都加上 $z$。
4 x,表示求以 $x$ 为根节点的子树内所有节点值之和。
第一行包含 $4$ 个正整数 $N,M,R,P$,分别表示树的结点个数、操作个数、根节点序号和取模数(即所有的输出结果均对此取模)。
接下来一行包含 $N$ 个非负整数,分别依次表示各个节点上初始的数值。
接下来 $N-1$ 行每行包含两个整数 $x,y$,表示点 $x$ 和点 $y$ 之间连有一条边(保证无环且连通)。
接下来 $M$ 行每行包含若干个正整数,每行表示一个操作。
输出包含若干行,分别依次表示每个操作 $2$ 或操作 $4$ 所得的结果(对 $P$ 取模)。
5 5 2 24
7 3 7 8 0
1 2
1 5
3 1
4 1
3 4 2
3 2 2
4 5
1 5 1 3
2 1 3
2
21
【数据规模】
对于 $30\%$ 的数据: $1 \leq N \leq 10$,$1 \leq M \leq 10$;
对于 $70\%$ 的数据: $1 \leq N \leq {10}^3$,$1 \leq M \leq {10}^3$;
对于 $100\%$ 的数据: $1\le N \leq {10}^5$,$1\le M \leq {10}^5$,$1\le R\le N$,$1\le P \le 2^{30}$。所有输入的数均在 int 范围内。
【样例说明】
树的结构如下:

各个操作如下:

故输出应依次为 $2$ 和 $21$。
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<cstdio>
#define Rint register int
#define mem(a,b) memset(a,(b),sizeof(a))
#define Temp template<typename T>
using namespace std;
typedef long long LL;
Temp inline void read(T &x){
x=0;T w=1,ch=getchar();
while(!isdigit(ch)&&ch!='-')ch=getchar();
if(ch=='-')w=-1,ch=getchar();
while(isdigit(ch))x=(x<<3)+(x<<1)+(ch^'0'),ch=getchar();
x=x*w;
}
#define mid ((l+r)>>1)
#define lson rt<<1,l,mid
#define rson rt<<1|1,mid+1,r
#define len (r-l+1)
const int maxn=200000+10;
int n,m,r,mod;
//见题意
int e,beg[maxn],nex[maxn],to[maxn],w[maxn],wt[maxn];
//链式前向星数组,w[]、wt[]初始点权数组
int a[maxn<<2],laz[maxn<<2];
//线段树数组、lazy操作
int son[maxn],id[maxn],fa[maxn],cnt,dep[maxn],siz[maxn],top[maxn];
//son[]重儿子编号,id[]新编号,fa[]父亲节点,cnt dfs_clock/dfs序,dep[]深度,siz[]子树大小,top[]当前链顶端节点
int res=0;
//查询答案
inline void add(int x,int y){//链式前向星加边
to[++e]=y;
nex[e]=beg[x];
beg[x]=e;
}
//-------------------------------------- 以下为线段树
inline void pushdown(int rt,int lenn){
laz[rt<<1]+=laz[rt];
laz[rt<<1|1]+=laz[rt];
a[rt<<1]+=laz[rt]*(lenn-(lenn>>1));
a[rt<<1|1]+=laz[rt]*(lenn>>1);
a[rt<<1]%=mod;
a[rt<<1|1]%=mod;
laz[rt]=0;
}
inline void build(int rt,int l,int r){
if(l==r){
a[rt]=wt[l];
if(a[rt]>mod)a[rt]%=mod;
return;
}
build(lson);
build(rson);
a[rt]=(a[rt<<1]+a[rt<<1|1])%mod;
}
inline void query(int rt,int l,int r,int L,int R){
if(L<=l&&r<=R){res+=a[rt];res%=mod;return;}
else{
if(laz[rt])pushdown(rt,len);
if(L<=mid)query(lson,L,R);
if(R>mid)query(rson,L,R);
}
}
inline void update(int rt,int l,int r,int L,int R,int k){
if(L<=l&&r<=R){
laz[rt]+=k;
a[rt]+=k*len;
}
else{
if(laz[rt])pushdown(rt,len);
if(L<=mid)update(lson,L,R,k);
if(R>mid)update(rson,L,R,k);
a[rt]=(a[rt<<1]+a[rt<<1|1])%mod;
}
}
//---------------------------------以上为线段树
inline int qRange(int x,int y){
int ans=0;
while(top[x]!=top[y]){//当两个点不在同一条链上
if(dep[top[x]]<dep[top[y]])swap(x,y);//把x点改为所在链顶端的深度更深的那个点
res=0;
query(1,1,n,id[top[x]],id[x]);//ans加上x点到x所在链顶端 这一段区间的点权和
ans+=res;
ans%=mod;//按题意取模
x=fa[top[x]];//把x跳到x所在链顶端的那个点的上面一个点
}
//直到两个点处于一条链上
if(dep[x]>dep[y])swap(x,y);//把x点深度更深的那个点
res=0;
query(1,1,n,id[x],id[y]);//这时再加上此时两个点的区间和即可
ans+=res;
return ans%mod;
}
inline void updRange(int x,int y,int k){//同上
k%=mod;
while(top[x]!=top[y]){
if(dep[top[x]]<dep[top[y]])swap(x,y);
update(1,1,n,id[top[x]],id[x],k);
x=fa[top[x]];
}
if(dep[x]>dep[y])swap(x,y);
update(1,1,n,id[x],id[y],k);
}
inline int qSon(int x){
res=0;
query(1,1,n,id[x],id[x]+siz[x]-1);//子树区间右端点为id[x]+siz[x]-1
return res;
}
inline void updSon(int x,int k){//同上
update(1,1,n,id[x],id[x]+siz[x]-1,k);
}
inline void dfs1(int x,int f,int deep){//x当前节点,f父亲,deep深度
dep[x]=deep;//标记每个点的深度
fa[x]=f;//标记每个点的父亲
siz[x]=1;//标记每个非叶子节点的子树大小
int maxson=-1;//记录重儿子的儿子数
for(Rint i=beg[x];i;i=nex[i]){
int y=to[i];
if(y==f)continue;//若为父亲则continue
dfs1(y,x,deep+1);//dfs其儿子
siz[x]+=siz[y];//把它的儿子数加到它身上
if(siz[y]>maxson)son[x]=y,maxson=siz[y];//标记每个非叶子节点的重儿子编号
}
}
inline void dfs2(int x,int topf){//x当前节点,topf当前链的最顶端的节点
id[x]=++cnt;//标记每个点的新编号
wt[cnt]=w[x];//把每个点的初始值赋到新编号上来
top[x]=topf;//这个点所在链的顶端
if(!son[x])return;//如果没有儿子则返回
dfs2(son[x],topf);//按先处理重儿子,再处理轻儿子的顺序递归处理
for(Rint i=beg[x];i;i=nex[i]){
int y=to[i];
if(y==fa[x]||y==son[x])continue;
dfs2(y,y);//对于每一个轻儿子都有一条从它自己开始的链
}
}
int main(){
read(n);read(m);read(r);read(mod);
for(Rint i=1;i<=n;i++)read(w[i]);
for(Rint i=1;i<n;i++){
int a,b;
read(a);read(b);
add(a,b);add(b,a);
}
dfs1(r,0,1);
dfs2(r,r);
build(1,1,n);
while(m--){
int k,x,y,z;
read(k);
if(k==1){
read(x);read(y);read(z);
updRange(x,y,z);
}
else if(k==2){
read(x);read(y);
printf("%d\n",qRange(x,y));
}
else if(k==3){
read(x);read(y);
updSon(x,y);
}
else{
read(x);
printf("%d\n",qSon(x));
}
}
}
青蛙。
给你一个长为 $n$ 的序列 $a$,有 $m$ 次询问,每次询问给定 $l,r,x$,求 $[l,r]$ 区间中小于等于 $x$ 的元素个数。
第一行两个数 $n,m$。
第二行 $n$ 个数表示序列 $a$。
之后 $m$ 行,每行三个数 $l,r,x$ 表示一次询问。
对每个询问,输出一行一个数表示答案。
6 4
1 1 4 5 1 4
1 6 3
1 6 4
1 1 4
1 5 4
3
5
1
4
对于 $20\%$ 的数据,满足 $1\le n,m,a_i,l,r,x\le 100$。
对于 $40\%$ 的数据,满足 $1\le n,m,a_i,l,r,x\le 10^4$。
对于 $60\%$ 的数据,满足 $1\le n,m,a_i,l,r,x\le 10^5$。
对于 $80\%$ 的数据,满足 $1\le n,m,a_i,l,r,x\le 10^6$。
对于 $100\%$ 的数据,满足 $1\le n,m,a_i,l,r,x\le 2\times10^6$。
#include<bits/stdc++.h>
using namespace std;
struct node{
int x,id,val;
};
int lowbit(int i){
return i&(-i);
}
int f[2000005];
void add(int x){
for(int i=x;i<=2000000;i+=lowbit(i))f[i]++;
}
int ask(int x){
int ans=0;
for(int i=x;i>=1;i-=lowbit(i))ans+=f[i];
return ans;
}
vector<node>vec[2000005];
int ans[2000005],n,m,a[2000006];
int main(){
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
cin>>n>>m;
for(int i=1;i<=n;i++)cin>>a[i];
for(int i=1;i<=m;i++){
int l,r,x;
cin>>l>>r>>x;
vec[l-1].push_back({x,i,-1});
vec[r].push_back({x,i,1});
}
for(int i=1;i<=n;i++){
add(a[i]);
for(int j=0;j<vec[i].size();j++){
ans[vec[i][j].id]+=vec[i][j].val*ask(vec[i][j].x);
}
}
for(int i=1;i<=m;i++)cout<<ans[i]<<"\n";
return 0;
}
求 $1\sim N$ 的一个给定全排列在所有 $1\sim N$ 全排列中的排名。结果对 $998244353$ 取模。
第一行一个正整数 $N$。
第二行 $N$ 个正整数,表示 $1\sim N$ 的一种全排列。
一行一个非负整数,表示答案对 $998244353$ 取模的值。
3
2 1 3
3
4
1 2 4 3
2
对于 $10\%$ 数据,$1\le N\le 10$。
对于 $50\%$ 数据,$1\le N\le 5000$。
对于 $100\%$ 数据,$1\le N\le 1000000$。
#include<bits/stdc++.h>
using namespace std;
const int maxn=1000005;//上界
const int Mod=998244353;//神圣的模数
typedef long long ll;//加上这个很有用的,可以避免过多的重复long long
int n;
ll jc[maxn];//阶乘
ll tree[maxn];//树状数组
ll lowbit(ll x){return x&(-x);}//树状数组实现的支撑-取最低位,不知道的请翻到最后
ll sum(ll x)//求和
{
ll ans=0;
while(x!=0)
{
ans+=tree[x]%Mod;
x-=lowbit(x);
}
return ans%Mod;
}
void add(ll x,ll k)//加法
{
while(x<=n)
{
tree[x]+=k;
x+=lowbit(x);
}
}
int main()
{
scanf("%d",&n);
jc[0]=1;
for(int i=1;i<=n;i++)//预处理阶乘
{
jc[i]=jc[i-1]*i%Mod;
jc[i]%=Mod;
}
for(int i=1;i<=n;i++)
{
add(i,1);//如前面所说的那样,每一位都加上1
}
ll ans=1;//求排名,所以位置的值为1
for(int i=1;i<=n;i++)
{
ll a;
scanf("%lld",&a);//读入
ans+=((sum(a)-1)*jc[n-i]%Mod)%Mod;//取模运算分进去,不知道的往后看
add(a,-1);//这一个位置的值出现了,就把他减掉
}
printf("%lld\n",ans%Mod);
return 0;
}
您需要动态地维护一个可重集合 $M$,并且提供以下操作:
对于操作 3,5,6,不保证当前可重集中存在数 $x$。
第一行为 $n$,表示操作的个数,下面 $n$ 行每行有两个数 $\text{opt}$ 和 $x$,$\text{opt}$ 表示操作的序号($ 1 \leq \text{opt} \leq 6 $)
对于操作 $3,4,5,6$ 每行输出一个数,表示对应答案。
10
1 106465
4 1
1 317721
1 460929
1 644985
1 84185
1 89851
6 81968
1 492737
5 493598
106465
84185
492737
【数据范围】
对于 $100\%$ 的数据,$1\le n \le 10^5$,$|x| \le 10^7$
来源:Tyvj1728 原名:普通平衡树
在此鸣谢
#include<iostream>
#include<cstdio>
#include<queue>
#include<cstring>
#include<algorithm>
#include<climits>
typedef long long LL;
using namespace std;
int RD(){
int out = 0,flag = 1;char c = getchar();
while(c < '0' || c >'9'){if(c == '-')flag = -1;c = getchar();}
while(c >= '0' && c <= '9'){out = out * 10 + c - '0';c = getchar();}
return flag * out;
}
//第一次打treap,不压行写注释XD
const int maxn = 1000019,INF = 1e9;
//平衡树,利用BST性质查询和修改,利用随机和堆优先级来保持平衡,把树的深度控制在log N,保证了操作效率
//基本平衡树有以下几个比较重要的函数:新建,插入,删除,旋转
//节点的基本属性有val(值),dat(随机出来的优先级)
//通过增加属性,结合BST的性质可以达到一些效果,如size(子树大小,查询排名),cnt(每个节点包含的副本数)等
int na;
int ch[maxn][2];//[i][0]代表i左儿子,[i][1]代表i右儿子
int val[maxn],dat[maxn];
int size[maxn],cnt[maxn];
int tot,root;
int New(int v){//新增节点,
val[++tot] = v;//节点赋值
dat[tot] = rand();//随机优先级
size[tot] = 1;//目前是新建叶子节点,所以子树大小为1
cnt[tot] = 1;//新建节点同理副本数为1
return tot;
}
void pushup(int id){//和线段树的pushup更新一样
size[id] = size[ch[id][0]] + size[ch[id][1]] + cnt[id];//本节点子树大小 = 左儿子子树大小 + 右儿子子树大小 + 本节点副本数
}
void build(){
root = New(-INF),ch[root][1] = New(INF);//先加入正无穷和负无穷,便于之后操作(貌似不加也行)
pushup(root);//因为INF > -INF,所以是右子树,
}
void Rotate(int &id,int d){//id是引用传递,d(irection)为旋转方向,0为左旋,1为右旋
int temp = ch[id][d ^ 1];//旋转理解:找个动图看一看就好(或参见其他OIer的blog)
ch[id][d ^ 1] = ch[temp][d];//这里讲一个记忆技巧,这些数据都是被记录后马上修改
ch[temp][d] = id;//所以像“Z”一样
id = temp;//比如这个id,在上一行才被记录过,ch[temp][d]、ch[id][d ^ 1]也是一样的
pushup(ch[id][d]),pushup(id);//旋转以后size会改变,看图就会发现只更新自己和转上来的点,pushup一下,注意先子节点再父节点
}//旋转实质是({在满足BST的性质的基础上比较优先级}通过交换本节点和其某个叶子节点)把链叉开成二叉形状(从而控制深度),可以看图理解一下
void insert(int &id,int v){//id依然是引用,在新建节点时可以体现
if(!id){
id = New(v);//若节点为空,则新建一个节点
return ;
}
if(v == val[id])cnt[id]++;//若节点已存在,则副本数++;
else{//要满足BST性质,小于插到左边,大于插到右边
int d = v < val[id] ? 0 : 1;//这个d是方向的意思,按照BST的性质,小于本节点则向左,大于向右
insert(ch[id][d],v);//递归实现
if(dat[id] < dat[ch[id][d]])Rotate(id,d ^ 1);//(参考一下图)与左节点交换右旋,与右节点交换左旋
}
pushup(id);//现在更新一下本节点的信息
}
void Remove(int &id,int v){//最难de部分了
if(!id)return ;//到这了发现查不到这个节点,该点不存在,直接返回
if(v == val[id]){//检索到了这个值
if(cnt[id] > 1){cnt[id]--,pushup(id);return ;}//若副本不止一个,减去一个就好
if(ch[id][0] || ch[id][1]){//发现只有一个值,且有儿子节点,我们只能把值旋转到底部删除
if(!ch[id][1] || dat[ch[id][0]] > dat[ch[id][1]]){//当前点被移走之后,会有一个新的点补上来(左儿子或右儿子),按照优先级,优先级大的补上来
Rotate(id,1),Remove(ch[id][1],v);//我们会发现,右旋是与左儿子交换,当前点变成右节点;左旋则是与右儿子交换,当前点变为左节点
}
else Rotate(id,0),Remove(ch[id][0],v);
pushup(id);
}
else id = 0;//发现本节点是叶子节点,直接删除
return ;//这个return对应的是检索到值de所有情况
}
v < val[id] ? Remove(ch[id][0],v) : Remove(ch[id][1],v);//继续BST性质
pushup(id);
}
int get_rank(int id,int v){
if(!id)return 1;//若查询值不存在,返回;因为最后要减一排除哨兵节点,想要结果为-1这里就返回0
if(v == val[id])return size[ch[id][0]] + 1;//查询到该值,由BST性质可知:该点左边值都比该点的值(查询值)小,故rank为左儿子大小 + 1
else if(v < val[id])return get_rank(ch[id][0],v);//发现需查询的点在该点左边,往左边递归查询
else return size[ch[id][0]] + cnt[id] + get_rank(ch[id][1],v);//若查询值大于该点值。说明询问点在当前点的右侧,且此点的值都小于查询值,所以要加上cnt[id]
}
int get_val(int id,int rank){
if(!id)return INF;//一直向右找找不到,说明是正无穷
if(rank <= size[ch[id][0]])return get_val(ch[id][0],rank);//左边排名已经大于rank了,说明rank对应的值在左儿子那里
else if(rank <= size[ch[id][0]] + cnt[id])return val[id];//上一步排除了在左区间的情况,若是rank在左与中(目前节点)中,则直接返回目前节点(中区间)的值
else return get_val(ch[id][1],rank - size[ch[id][0]] - cnt[id]);//剩下只能在右区间找了,rank减去左区间大小和中区间,继续递归
}
int get_pre(int v){
int id = root,pre;//递归不好返回,以循环求解
while(id){//查到节点不存在为止
if(val[id] < v)pre = val[id],id = ch[id][1];//满足当前节点比目标小,往当前节点的右侧寻找最优值
else id = ch[id][0];//无论是比目标节点大还是等于目标节点,都不满足前驱条件,应往更小处靠近
}
return pre;
}
int get_next(int v){
int id = root,next;
while(id){
if(val[id] > v)next = val[id],id = ch[id][0];//同理,满足条件向左寻找更小解(也就是最优解)
else id = ch[id][1];//与上方同理
}
return next;
}
int main(){
build();//不要忘记初始化[运行build()会连同root一并初始化,所以很重要]
na = RD();
for(int i = 1;i <= na;i++){
int cmd = RD(),x = RD();
if(cmd == 1)insert(root,x);//函数都写好了,注意:需要递归的函数都从根开始,不需要递归的函数直接查询
else if(cmd == 2)Remove(root,x);
else if(cmd == 3)printf("%d\n",get_rank(root,x) - 1);//注意:因为初始化时插入了INF和-INF,所以查询排名时要减1(-INF不是第一小,是“第零小”)
else if(cmd == 4)printf("%d\n",get_val(root,x + 1));//同理,用排名查询值得时候要查x + 1名,因为第一名(其实不是)是-INF
else if(cmd == 5)printf("%d\n",get_pre(x));
else if(cmd == 6)printf("%d\n",get_next(x));
}
return 0;
}
您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作:
-2147483647);2147483647)。对于一组元素,一个数的排名被定义为严格比它小的元素个数加一,而排名为 $k$ 的数被定义为“将元素从小到大排序后排在第 $k$ 位的元素值”。
第一行两个数 $n,m$,表示长度为 $n$ 的有序序列和 $m$ 个操作。
第二行有 $n$ 个数,表示有序序列。
下面有 $m$ 行,$opt$ 表示操作标号。
若 $opt=1$,则为操作 $1$,之后有三个数 $l~r~k$,表示查询 $k$ 在区间 $[l,r]$ 的排名。
若 $opt=2$,则为操作 $2$,之后有三个数 $l~r~k$,表示查询区间 $[l,r]$ 内排名为 $k$ 的数。
若 $opt=3$,则为操作 $3$,之后有两个数 $pos~k$,表示将 $pos$ 位置的数修改为 $k$。
若 $opt=4$,则为操作 $4$,之后有三个数 $l~r~k$,表示查询区间 $[l,r]$ 内 $k$ 的前驱。
若 $opt=5$,则为操作 $5$,之后有三个数 $l~r~k$,表示查询区间 $[l,r]$ 内 $k$ 的后继。
对于操作 $1,2,4,5$,各输出一行,表示查询结果。
9 6
4 2 2 1 9 4 0 1 1
2 1 4 3
3 4 10
2 1 4 3
1 2 5 9
4 3 9 5
5 2 8 5
2
4
3
4
9
$1\le n,m\le5\times 10^4$,序列中的值在任何时刻 $\in[0,10^8]$。
题目来源:bzoj3196 / Tyvj1730,在此鸣谢。
此数据为洛谷原创。(特别提醒:此数据不保证操作 4、5 一定存在,故请务必考虑不存在的情况。)
#include<cstdio>
#include<algorithm>
#include<map>
using namespace std;const int N=5*1e4+10;const int M=1e5+10;
const int B=260;const int B2=300;int a[N];//维护的表格
int cnt1[N/B+3][M/B2+3];int cnt2[N/B+3][M];int n;int m;int bi[N];int bi1[M];
int tr1[M];int tr2[M];map <int,int> mp;int S;int Pr[M];int Pl[M];int val[M];
inline int frk(int l,int r,int va)//查询元素的排名
{
int p1=bi[l];int p2=bi[r];int ret=0;
if(p1==p2){for(int i=l;i<=r;i++)ret+=(a[i]<va);return ret+1;}
for(int i=l;bi[i]==p1;i++)ret+=(a[i]<va);
for(int i=r;bi[i]==p2;i--)ret+=(a[i]<va);p2--;
for(int i=1;i<bi1[va];i++)ret+=cnt1[p2][i];
for(int i=1;i<bi1[va];i++)ret-=cnt1[p1][i];
for(int i=va-1;bi1[i]==bi1[va];i--)ret+=cnt2[p2][i];
for(int i=va-1;bi1[i]==bi1[va];i--)ret-=cnt2[p1][i];return ret+1;
}
inline int ckth(const int& p1,const int& p2,int k)//辅助函数,查询kth
{
int ret=B2;int cur=0;
for(int t=1;cur<k;ret+=B2,t++)cur+=cnt1[p2][t]-cnt1[p1][t]+tr1[t];ret-=B2;
for(;cur>=k;ret--)cur-=cnt2[p2][ret]-cnt2[p1][ret]+tr2[ret];return ret+1;
}
inline int cpre(const int& p1,const int& p2,int k)//辅助函数,查询前驱
{
for(int i=k-1;bi1[i]==bi1[k];i--)
if(cnt2[p2][i]-cnt2[p1][i]+tr2[i])return i;
int p;for(p=bi1[k]-1;(cnt1[p2][p]-cnt1[p1][p]+tr1[p])==0;p--);
for(int i=Pr[p];;i--)if(cnt2[p2][i]-cnt2[p1][i]+tr2[i])return i;
}
inline int csuf(const int& p1,const int& p2,int k)//辅助函数,查询后继
{
for(int i=k+1;bi1[i]==bi1[k];i++)
if(cnt2[p2][i]-cnt2[p1][i]+tr2[i])return i;
int p;for(p=bi1[k]+1;(cnt1[p2][p]-cnt1[p1][p]+tr1[p])==0;p++);
for(int i=Pl[p];;i++)if(cnt2[p2][i]-cnt2[p1][i]+tr2[i])return i;
}
# define ins(x) tr1[bi1[x]]++,tr2[x]++
# define del(x) tr1[bi1[x]]--,tr2[x]--
inline int calc(int l,int r,int k,int(*f)(const int& p1,const int& p2,int k))//这里用了个函数指针
{
int p1=bi[l];int p2=bi[r];int ret=0;//直接处理出区间的cnt1,cnt2数组
if(p1==p2)
{
for(int i=l;i<=r;i++)ins(a[i]);ret=f(p1,p2,k);
for(int i=l;i<=r;i++)del(a[i]);return val[ret];
}
for(int i=l;bi[i]==p1;i++)ins(a[i]);
for(int i=r;bi[i]==p2;i--)ins(a[i]);ret=f(p1,p2-1,k);
for(int i=l;bi[i]==p1;i++)del(a[i]);
for(int i=r;bi[i]==p2;i--)del(a[i]);return val[ret];//记得还原回离散化之前的值
}
inline void modify(int pos,int y)//暴力修改
{
int p=bi1[a[pos]];for(int i=bi[pos];i<=bi[n];i++)cnt1[i][p]--;
p=a[pos];for(int i=bi[pos];i<=bi[n];i++)cnt2[i][p]--;
p=bi1[y];for(int i=bi[pos];i<=bi[n];i++)cnt1[i][p]++;
for(int i=bi[pos];i<=bi[n];i++)cnt2[i][y]++;a[pos]=y;
}
struct opt{int tp;int l;int r;int k;}op[N];
int main()
{
scanf("%d%d",&n,&m);mp[-2147483647]=1;mp[2147483647]=1;
for(int i=1;i<=n;i++)scanf("%d",&a[i]),mp[a[i]]=1;
for(int i=1;i<=m;i++)
{
scanf("%d",&op[i].tp);
if(op[i].tp!=3)scanf("%d%d%d",&op[i].l,&op[i].r,&op[i].k);
else scanf("%d%d",&op[i].l,&op[i].k);if(op[i].tp!=2)mp[op[i].k]=1;
}
S=mp.size();map <int,int> :: iterator it,it1;//离散化
for(it=mp.begin(),it1=it,++it1;it1!=mp.end();++it,++it1)it1->second+=it->second;
for(it=mp.begin();it!=mp.end();++it)val[it->second]=it->first;
for(int i=1;i<=n;i++)a[i]=mp[a[i]];
for(int i=1;i<=m;i++)if(op[i].tp!=2)op[i].k=mp[op[i].k];
for(int i=1;i<=n;i++)bi[i]=(i-1)/B+1;for(int i=1;i<=S;i++)bi1[i]=(i-1)/B2+1;
for(int i=1;i<=S;i++)Pr[bi1[i]]=i;for(int i=S;i>=1;i--)Pl[bi1[i]]=i;
for(int i=1;i<=n;i++)
{
int p=bi1[a[i]];for(int j=bi[i];j<=bi[n];j++)cnt1[j][p]++;
p=a[i];for(int j=bi[i];j<=bi[n];j++)cnt2[j][p]++;
}ins(1);ins(S);//插入哨兵
for(int i=1;i<=m;i++)
switch(op[i].tp)
{
case 1:{printf("%d\n",frk(op[i].l,op[i].r,op[i].k));break;}
case 2:{printf("%d\n",calc(op[i].l,op[i].r,op[i].k+1,ckth));break;}
case 3:{modify(op[i].l,op[i].k);break;}
case 4:{printf("%d\n",calc(op[i].l,op[i].r,op[i].k,cpre));break;}
case 5:{printf("%d\n",calc(op[i].l,op[i].r,op[i].k,csuf));break;}
}return 0;//拜拜程序~
}
如题,已知一个数列 $a$,你需要进行下面三种操作:
第一行包含三个整数 $n,q,m$,分别表示该数列数字的个数、操作的总个数和模数。
第二行包含 $n$ 个用空格分隔的整数,其中第 $i$ 个数字表示数列第 $i$ 项的初始值 $a_i$。
接下来 $q$ 行每行包含若干个整数,表示一个操作,具体如下:
操作 $1$: 格式:1 x y k 含义:将区间 $[x,y]$ 内每个数乘上 $k$。
操作 $2$: 格式:2 x y k 含义:将区间 $[x,y]$ 内每个数加上 $k$。
操作 $3$: 格式:3 x y 含义:输出区间 $[x,y]$ 内每个数的和对 $m$ 取模所得的结果。
输出包含若干行整数,即为所有操作 $3$ 的结果。
5 5 38
1 5 4 2 3
2 1 4 1
3 2 5
1 2 4 2
2 3 5 5
3 1 4
17
2
【数据范围】
对于 $30\%$ 的数据:$n \le 8$,$q \le 10$。
对于 $70\%$ 的数据:$n \le 10^3 $,$q \le 10^4$。
对于 $100\%$ 的数据:$1 \le n \le 10^5$,$1 \le q \le 10^5,1\le a_i,k\le 10^4$。
除样例外,$m = 571373$。
(数据已经过加强 ^_^)
样例说明:
故输出应为 $17$、$2$($40 \bmod 38 = 2$)。
#include <bits/stdc++.h>
#define MAXN 100010
#define ll long long
using namespace std;
int n, m, mod;
int a[MAXN];
struct Segment_Tree {
ll sum, add, mul;
int l, r;
}s[MAXN * 4];
void update(int pos) {
s[pos].sum = (s[pos << 1].sum + s[pos << 1 | 1].sum) % mod;
return;
}
void pushdown(int pos) { //pushdown的维护
s[pos << 1].sum = (s[pos << 1].sum * s[pos].mul + s[pos].add * (s[pos << 1].r - s[pos << 1].l + 1)) % mod;
s[pos << 1 | 1].sum = (s[pos << 1 | 1].sum * s[pos].mul + s[pos].add * (s[pos << 1 | 1].r - s[pos << 1 | 1].l + 1)) % mod;
s[pos << 1].mul = (s[pos << 1].mul * s[pos].mul) % mod;
s[pos << 1 | 1].mul = (s[pos << 1 | 1].mul * s[pos].mul) % mod;
s[pos << 1].add = (s[pos << 1].add * s[pos].mul + s[pos].add) % mod;
s[pos << 1 | 1].add = (s[pos << 1 | 1].add * s[pos].mul + s[pos].add) % mod;
s[pos].add = 0;
s[pos].mul = 1;
return;
}
void build_tree(int pos, int l, int r) { //建树
s[pos].l = l;
s[pos].r = r;
s[pos].mul = 1;
if (l == r) {
s[pos].sum = a[l] % mod;
return;
}
int mid = (l + r) >> 1;
build_tree(pos << 1, l, mid);
build_tree(pos << 1 | 1, mid + 1, r);
update(pos);
return;
}
void ChangeMul(int pos, int x, int y, int k) { //区间乘法
if (x <= s[pos].l && s[pos].r <= y) {
s[pos].add = (s[pos].add * k) % mod;
s[pos].mul = (s[pos].mul * k) % mod;
s[pos].sum = (s[pos].sum * k) % mod;
return;
}
pushdown(pos);
int mid = (s[pos].l + s[pos].r) >> 1;
if (x <= mid) ChangeMul(pos << 1, x, y, k);
if (y > mid) ChangeMul(pos << 1 | 1, x, y, k);
update(pos);
return;
}
void ChangeAdd(int pos, int x, int y, int k) { //区间加法
if (x <= s[pos].l && s[pos].r <= y) {
s[pos].add = (s[pos].add + k) % mod;
s[pos].sum = (s[pos].sum + k * (s[pos].r - s[pos].l + 1)) % mod;
return;
}
pushdown(pos);
int mid = (s[pos].l + s[pos].r) >> 1;
if (x <= mid) ChangeAdd(pos << 1, x, y, k);
if (y > mid) ChangeAdd(pos << 1 | 1, x, y, k);
update(pos);
return;
}
ll AskRange(int pos, int x, int y) { //区间询问
if (x <= s[pos].l && s[pos].r <= y) {
return s[pos].sum;
}
pushdown(pos);
ll val = 0;
int mid = (s[pos].l + s[pos].r) >> 1;
if (x <= mid) val = (val + AskRange(pos << 1, x, y)) % mod;
if (y > mid) val = (val + AskRange(pos << 1 | 1, x, y)) % mod;
return val;
}
int main() {
scanf("%d%d%d", &n, &m, &mod);
for (int i = 1; i <= n; i++) {
scanf("%d", &a[i]);
}
build_tree(1, 1, n);
for (int i = 1; i <= m; i++) {
int opt, x, y;
scanf("%d%d%d", &opt, &x, &y);
if (opt == 1) {
int k;
scanf("%d", &k);
ChangeMul(1, x, y, k);
}
if (opt == 2) {
int k;
scanf("%d", &k);
ChangeAdd(1, x, y, k);
}
if (opt == 3) {
printf("%lld\n", AskRange(1, x, y));
}
}
return 0;
}
本题是线段树维护区间最值操作与区间历史最值的模板。
给出一个长度为 $n$ 的数列 $A$,同时定义一个辅助数组 $B$,$B$ 开始与 $A$ 完全相同。接下来进行了 $m$ 次操作,操作有五种类型,按以下格式给出:
1 l r k:对于所有的 $i\in[l,r]$,将 $A_i$ 加上 $k$($k$ 可以为负数)。2 l r v:对于所有的 $i\in[l,r]$,将 $A_i$ 变成 $\min(A_i,v)$。3 l r:求 $\sum_{i=l}^{r}A_i$。4 l r:对于所有的 $i\in[l,r]$,求 $A_i$ 的最大值。5 l r:对于所有的 $i\in[l,r]$,求 $B_i$ 的最大值。在每一次操作后,我们都进行一次更新,让 $B_i\gets\max(B_i,A_i)$。
第一行包含两个正整数 $n,m$,分别表示数列 $A$ 的长度和操作次数。
第二行包含 $n$ 个整数 $A_1,A_2,\cdots,A_n$,表示数列 $A$。
接下来 $m$ 行,每行行首有一个整数 $op$,表示操作类型;接下来两个或三个整数表示操作参数,格式见【题目描述】。
对于 $op\in\{3,4,5\}$ 的操作,输出一行包含一个整数,表示这个询问的答案。
5 6
1 2 3 4 5
3 2 5
1 1 3 3
4 2 4
2 3 4 1
5 1 5
3 1 4
14
6
6
11
| 操作次数 | 输入内容 | 操作 | 数列 | 输出结果 |
|---|---|---|---|---|
| 0 | $1,2,3,4,5$ | |||
| 1 | 3 2 5 |
求出 $[2,5]$ 所有数的和 | $1,2,3,4,5$ | 14 |
| 2 | 1 1 3 3 |
将 $[1,3]$ 内所有数加 $3$ | $4,5,6,4,5$ | |
| 3 | 4 2 4 |
求出 $[2,4]$ 所有数的最大值 | $4,5,6,4,5$ | 6 |
| 4 | 2 3 4 1 |
将 $[3,4]$ 所有数与 $1$ 取最小值 | $4,5,1,1,5$ | |
| 5 | 5 1 5 |
求出 $[1,5]$ 所有位置历史最大值的最大值 | $4,5,1,1,5$ | 6 |
| 6 | 3 1 4 |
求出 $[1,4]$ 所有数的和 | $4,5,1,1,5$ | 11 |
本题输入量较大,请使用合理高效的读入方法。
/*
this code is made by warzone
2022.2.14 21:25
*/
#include<stdio.h>
#include<string.h>
typedef long long ll;
typedef unsigned int word;
struct READ{//快读
char pool[5<<22],*top,w;
inline READ(){fread(top=pool,5<<22,1,stdin);}
template<typename type>
inline READ& operator >>(type& num){
for(w=1;'0'>*top||*top>'9';)
w=*(top++)=='-'? -1:1;
for(num=0;'0'<=*top&&*top<='9';)
num=num*10+(*(top++)-'0');
return num*=w,*this;
}
}cin;
const int inf=0x80000000;//−∞
inline int max(const int a,const int b){
return a>b? a:b;}
/* 向量/矩阵
⎡a⎤ ⎡a −∞⎤
⎣b⎦ ⎣b 0⎦
*/
struct matrix{
int a,b;
inline matrix(){}
inline matrix(const matrix &p)=default;
inline matrix(int A,int B):a(A),b(B){}
inline matrix operator+(const matrix &p)const{//矩阵/向量 加法
return matrix(max(a,p.a),max(b,p.b));}
inline matrix operator()(const matrix &p)const{//矩阵乘法
return matrix(a==inf||p.a==inf? inf:a+p.a,
b==inf||p.a==inf? p.b:max(b+p.a,p.b));}
inline bool operator!=(const matrix &p)const{
return a!=p.a||b!=p.b;}
}const I(0,inf),vec0(inf,inf);
word n,m;
struct segment_tree{//线段树(zkw)
ll sum[1u<<20];
int cnt[1u<<20];
matrix mx[1u<<20],M[1u<<20];
matrix se[1u<<20],E[1u<<20];
inline segment_tree(){
for(word i=0;i<(1u<<20);++i) M[i]=E[i]=I;
se[1u<<19]=vec0,cnt[1u<<19]=1,cin>>n>>m;
for(int i=(1u<<19)+1,num;i<=(1u<<19|n);++i){
se[i]=vec0,cnt[i]=1,cin>>num;
sum[i]=mx[i].a=mx[i].b=num;
}
for(word i=(1u<<19|n)+1;i<(1u<<20);++i)
se[i]=vec0,cnt[i]=1;
for(word i=(1u<<19)-1;i;--i) pushup(i);
}
#define l (rt<<1)
#define r (rt<<1|1)
inline void pushup(const word rt){//上传信息
sum[rt]=sum[l]+sum[r];
if(mx[l].a>mx[r].a){
mx[rt]=mx[l],cnt[rt]=cnt[l];
se[rt]=se[l]+se[r]+mx[r];
}else if(mx[l].a<mx[r].a){
mx[rt]=mx[r],cnt[rt]=cnt[r];
se[rt]=se[l]+se[r]+mx[l];
}else{
mx[rt]=mx[l]+mx[r];
cnt[rt]=cnt[l]+cnt[r];
se[rt]=se[l]+se[r];
}
}
inline void Mmul(const matrix &p,const word id){//修改 mx
mx[id]=p(mx[id]),M[id]=p(M[id]),sum[id]+=1ll*cnt[id]*p.a;}
inline void Emul(const matrix &p,const word id,const word size){//修改 se
se[id]=p(se[id]),E[id]=p(E[id]);
sum[id]+=1ll*(size-cnt[id])*p.a;
}
inline void pushdown(const word rt,const word size){//下传标记
Mmul(mx[l].a==mx[rt].a-M[rt].a? M[rt]:E[rt],l);
Mmul(mx[r].a==mx[rt].a-M[rt].a? M[rt]:E[rt],r);
//注意此处不能用 mx[l].a 和 mx[r].a 的大小关系来判断划分,因为标记下传后 mx 会被修改
if(size!=1) Emul(E[rt],l,size),Emul(E[rt],r,size);
M[rt]=E[rt]=I;
}
inline void plus(const word f,const word t,const int k,
const word rt=1,const word size=1u<<18){//区间加
if(size==0||(f==0&&t==(size<<1)-1))
return Mmul(matrix(k,k),rt),Emul(matrix(k,k),rt,size? size<<1:1);
auto lf=[&](word f,word t){plus(f,t,k,l,size>>1);};
auto rf=[&](word f,word t){plus(f,t,k,r,size>>1);};
pushdown(rt,size);
if(f&size) rf(f&~size,t&~size);
else if((t&size)^size) lf(f,t);
else lf(f,size-1),rf(0,t&~size);
pushup(rt);
}
inline void min(const word f,const word t,const int k,
const word rt=1,const word size=1u<<18){//区间取 min
if(k>=mx[rt].a) return;
const auto lf=[&](word f,word t){min(f,t,k,l,size>>1);};
const auto rf=[&](word f,word t){min(f,t,k,r,size>>1);};
if(size==0||(f==0&&t==(size<<1)-1)){
if(k>se[rt].a) return Mmul(matrix(k-mx[rt].a,k-mx[rt].a),rt);
return pushdown(rt,size),lf(0,size-1),rf(0,size-1),pushup(rt);
}
pushdown(rt,size);
if(f&size) rf(f&~size,t&~size);
else if((t&size)^size) lf(f,t);
else lf(f,size-1),rf(0,t&~size);
pushup(rt);
}
inline ll getsum(const word f,const word t,
const word rt=1,const word size=1u<<18){//区间求和
if(size==0||(f==0&&t==(size<<1)-1)) return sum[rt];
const auto lf=[&](word f,word t)->ll{return getsum(f,t,l,size>>1);};
const auto rf=[&](word f,word t)->ll{return getsum(f,t,r,size>>1);};
pushdown(rt,size);
if(f&size) return rf(f&~size,t&~size);
else if((t&size)^size) return lf(f,t);
return lf(f,size-1)+rf(0,t&~size);
}
inline int geta(const word f,const word t,
const word rt=1,const word size=1u<<18){//区间最值
if(size==0||(f==0&&t==(size<<1)-1)) return mx[rt].a;
const auto lf=[&](word f,word t)->ll{return geta(f,t,l,size>>1);};
const auto rf=[&](word f,word t)->ll{return geta(f,t,r,size>>1);};
pushdown(rt,size);
if(f&size) return rf(f&~size,t&~size);
else if((t&size)^size) return lf(f,t);
return max(lf(f,size-1),rf(0,t&~size));
}
inline int getb(const word f,const word t,
const word rt=1,const word size=1u<<18){//区间历史最值
if(size==0||(f==0&&t==(size<<1)-1)) return max(mx[rt].b,se[rt].b);
const auto lf=[&](word f,word t)->ll{return getb(f,t,l,size>>1);};
const auto rf=[&](word f,word t)->ll{return getb(f,t,r,size>>1);};
pushdown(rt,size);
if(f&size) return rf(f&~size,t&~size);
else if((t&size)^size) return lf(f,t);
return max(lf(f,size-1),rf(0,t&~size));
}
#undef l
#undef r
}tree;
int main(){
for(int opt,l,r;m;--m)
if(cin>>opt>>l>>r,opt==1)
cin>>opt,tree.plus(l,r,opt);
else if(opt==2) cin>>opt,tree.min(l,r,opt);
else if(opt==4) printf("%d\n",tree.geta(l,r));
else if(opt==5) printf("%d\n",tree.getb(l,r));
else printf("%lld\n",tree.getsum(l,r));
return 0;
}
标准库头文件 <algorithm>
C++ 标准库头文件
此头文件是算法库的一部分。
包含
<initializer_list>
(C++11)
std::initializer_list 类模板
类
定义于命名空间 std::ranges
返回类型 (C++20)
ranges::in_fun_result
(C++20)
提供了一种将迭代器和函数对象存储为单个单元的方法
(类模板)
ranges::in_in_result
(C++20)
提供了一种将两个迭代器存储为单个单元的方法
(类模板)
ranges::in_out_result
(C++20)
提供了一种将两个迭代器存储为单个单元的方法
(类模板)
ranges::in_in_out_result
(C++20)
提供了一种将三个迭代器存储为单个单元的方法
(类模板)
ranges::in_out_out_result
(C++20)
提供了一种将三个迭代器存储为单个单元的方法
(类模板)
ranges::min_max_result
(C++20)
提供了一种将两个相同类型的对象或引用存储为单个单元的方法
(类模板)
ranges::in_found_result
(C++20)
提供了一种将迭代器和布尔标志存储为单个单元的方法
(类模板)
ranges::in_value_result
(C++23)
提供了一种将迭代器和值存储为单个单元的方法
(类模板)
ranges::out_value_result
(C++23)
提供了一种将迭代器和值存储为单个单元的方法
(类模板)
函数
非修改序列操作
all_of
any_of
none_of
(C++11)
(C++11)
(C++11)
检查谓词对于范围中所有、任何或没有元素是否为真
(函数模板)
for_each
将一元函数对象应用于来自范围的元素
(函数模板)
for_each_n
(C++17)
将函数对象应用于序列的前 N 个元素
(函数模板)
count
count_if
返回满足特定条件的元素数量
(函数模板)
mismatch
查找两个范围不同的第一个位置
(函数模板)
find
find_if
find_if_not
(C++11)
查找满足特定条件的第一个元素
(函数模板)
find_end
查找某个范围中元素的最后一个序列
(函数模板)
find_first_of
搜索元素集合中的任何一个
(函数模板)
adjacent_find
查找第一个相等的相邻项(或满足给定谓词的相邻项)
(函数模板)
search
搜索元素范围的第一次出现
(函数模板)
search_n
搜索范围中连续重复元素一定次数的第一次出现
(函数模板)
修改序列操作
copy
copy_if
(C++11)
将元素范围复制到新位置
(函数模板)
copy_n
(C++11)
将一定数量的元素复制到新位置
(函数模板)
copy_backward
以向后顺序复制元素范围
(函数模板)
move
(C++11)
将元素范围移动到新位置
(函数模板)
move_backward
(C++11)
以向后顺序将元素范围移动到新位置
(函数模板)
fill
将给定值复制赋值给范围中的每个元素
(函数模板)
fill_n
将给定值复制赋值给范围中的 N 个元素
(函数模板)
transform
将函数应用于元素范围,并将结果存储在目标范围中
(函数模板)
generate
将连续函数调用的结果赋值给范围中的每个元素
(函数模板)
generate_n
将连续函数调用的结果赋值给范围中的 N 个元素
(函数模板)
remove
remove_if
移除满足特定条件的元素
(函数模板)
remove_copy
remove_copy_if
复制元素范围,省略那些满足特定条件的元素
(函数模板)
replace
replace_if
将所有满足特定条件的值替换为另一个值
(函数模板)
replace_copy
replace_copy_if
复制一个范围,将满足特定条件的元素替换为另一个值
(函数模板)
swap
交换两个对象的值
(函数模板)
swap_ranges
交换两个元素范围
(函数模板)
iter_swap
交换两个迭代器指向的元素
(函数模板)
reverse
反转范围中元素的顺序
(函数模板)
reverse_copy
创建一个反转的范围副本
(函数模板)
rotate
旋转范围中元素的顺序
(函数模板)
rotate_copy
复制并旋转元素范围
(函数模板)
shift_left
shift_right
(C++20)
移动范围中的元素
(函数模板)
random_shuffle
shuffle
(until C++17)
(C++11)
随机重新排序范围中的元素
(函数模板)
sample
(C++17)
从序列中选择 N 个随机元素
(函数模板)
unique
移除范围中连续重复的元素
(函数模板)
unique_copy
创建某个元素范围的副本,其中不包含连续重复项
(函数模板)
分区操作
is_partitioned
(C++11)
确定范围是否由给定谓词分区
(函数模板)
partition
将元素范围划分为两组
(函数模板)
partition_copy
(C++11)
复制一个范围,将元素划分为两组
(函数模板)
stable_partition
将元素划分为两组,同时保持其相对顺序
(函数模板)
partition_point
(C++11)
定位已分区范围的分区点
(函数模板)
排序操作
is_sorted
(C++11)
检查范围是否已排序为升序
(函数模板)
is_sorted_until
(C++11)
查找最大的已排序子范围
(函数模板)
sort
将范围排序为升序
(函数模板)
partial_sort
对范围的前 N 个元素进行排序
(函数模板)
partial_sort_copy
复制并部分排序元素范围
(函数模板)
stable_sort
排序元素范围,同时保持相等元素之间的顺序
(函数模板)
nth_element
部分排序给定范围,确保它按给定元素分区
(函数模板)
二分搜索操作 (在已排序范围上)
lower_bound
返回指向第一个不小于给定值的元素的迭代器
(function template)
upper_bound
返回指向首个大于某值的元素的迭代器
(function template)
binary_search
确定元素是否存在于部分有序的范围内
(function template)
equal_range
返回与特定键匹配的元素范围
(function template)
其他排序范围上的操作
merge
合并两个已排序的范围
(function template)
inplace_merge
就地合并两个有序范围
(function template)
集合操作(在已排序的范围上)
includes
如果一个序列是另一个序列的子序列,则返回 true
(function template)
set_difference
计算两个集合的差集
(function template)
set_intersection
计算两个集合的交集
(function template)
set_symmetric_difference
计算两个集合的对称差集
(function template)
set_union
计算两个集合的并集
(function template)
堆操作
is_heap
(C++11)
检查给定范围是否为最大堆
(function template)
is_heap_until
(C++11)
查找作为最大堆的最大子范围
(function template)
make_heap
从元素范围创建最大堆
(function template)
push_heap
向最大堆添加元素
(function template)
pop_heap
从最大堆中移除最大的元素
(function template)
sort_heap
将最大堆转换为升序排序的元素范围
(function template)
最小值/最大值操作
max
返回给定值中较大的那个
(function template)
max_element
返回范围中最大的元素
(function template)
min
返回给定值中较小的那个
(function template)
min_element
返回范围中最小的元素
(function template)
minmax
(C++11)
返回两个元素中较小和较大的那个
(function template)
minmax_element
(C++11)
返回范围中最小和最大的元素
(function template)
clamp
(C++17)
将值限制在边界值对之间
(function template)
比较操作
equal
确定两组元素是否相同
(function template)
lexicographical_compare
如果一个范围在字典序上小于另一个范围,则返回 true
(function template)
lexicographical_compare_three_way
(C++20)
使用三路比较比较两个范围
(function template)
排列操作
is_permutation
(C++11)
确定一个序列是否是另一个序列的排列
(function template)
next_permutation
生成元素范围的下一个更大的字典序排列
(function template)
prev_permutation
生成元素范围的下一个更小的字典序排列
(function template)
类似函数的实体 (C++20)
定义于命名空间 std::ranges
非修改序列操作
ranges::all_of
ranges::any_of
ranges::none_of
(C++20)
(C++20)
(C++20)
检查谓词对于范围中所有、任何或没有元素是否为真
(algorithm function object)
ranges::for_each
(C++20)
将一元函数对象应用于来自范围的元素
(algorithm function object)
ranges::for_each_n
(C++20)
将函数对象应用于序列的前 N 个元素
(algorithm function object)
ranges::count
ranges::count_if
(C++20)
(C++20)
返回满足特定条件的元素数量
(algorithm function object)
ranges::mismatch
(C++20)
查找两个范围不同的第一个位置
(algorithm function object)
ranges::find
ranges::find_if
ranges::find_if_not
(C++20)
(C++20)
(C++20)
查找满足特定条件的第一个元素
(algorithm function object)
ranges::find_last
ranges::find_last_if
ranges::find_last_if_not
(C++23)
(C++23)
(C++23)
查找满足特定条件的最后一个元素
(algorithm function object)
ranges::find_end
(C++20)
查找某个范围中元素的最后一个序列
(algorithm function object)
ranges::find_first_of
(C++20)
搜索元素集合中的任何一个
(algorithm function object)
ranges::adjacent_find
(C++20)
查找第一个相等的相邻项(或满足给定谓词的相邻项)
(algorithm function object)
ranges::search
(C++20)
搜索元素范围的第一次出现
(algorithm function object)
ranges::search_n
(C++20)
搜索范围中连续重复元素一定次数的第一次出现
(algorithm function object)
ranges::contains
ranges::contains_subrange
(C++23)
(C++23)
检查范围是否包含给定的元素或子范围
(algorithm function object)
ranges::starts_with
(C++23)
检查一个范围是否以另一个范围开始
(algorithm function object)
ranges::ends_with
(C++23)
检查一个范围是否以另一个范围结束
(algorithm function object)
折叠操作
ranges::fold_left
(C++23)
左折叠元素范围
(algorithm function object)
ranges::fold_left_first
(C++23)
使用第一个元素作为初始值左折叠元素范围
(algorithm function object)
ranges::fold_right
(C++23)
右折叠元素范围
(algorithm function object)
ranges::fold_right_last
(C++23)
使用最后一个元素作为初始值右折叠元素范围
(algorithm function object)
ranges::fold_left_with_iter
(C++23)
左折叠元素范围,并返回一个 pair (迭代器, 值)
(algorithm function object)
ranges::fold_left_first_with_iter
(C++23)
使用第一个元素作为初始值左折叠元素范围,并返回一个 pair (迭代器, optional)
(algorithm function object)
修改序列操作
ranges::copy
ranges::copy_if
(C++20)
(C++20)
将元素范围复制到新位置
(algorithm function object)
ranges::copy_n
(C++20)
将一定数量的元素复制到新位置
(algorithm function object)
ranges::copy_backward
(C++20)
以向后顺序复制元素范围
(algorithm function object)
ranges::move
(C++20)
将元素范围移动到新位置
(algorithm function object)
ranges::move_backward
(C++20)
以向后顺序将元素范围移动到新位置
(algorithm function object)
ranges::fill
(C++20)
为元素范围赋值
(algorithm function object)
ranges::fill_n
(C++20)
为若干元素赋值
(algorithm function object)
ranges::transform
(C++20)
将函数应用于元素范围
(algorithm function object)
ranges::generate
(C++20)
将函数结果保存在范围中
(algorithm function object)
ranges::generate_n
(C++20)
保存函数 N 次应用的结果
(algorithm function object)
ranges::remove
ranges::remove_if
(C++20)
(C++20)
移除满足特定条件的元素
(algorithm function object)
ranges::remove_copy
ranges::remove_copy_if
(C++20)
(C++20)
复制元素范围,省略那些满足特定条件的元素
(algorithm function object)
ranges::replace
ranges::replace_if
(C++20)
(C++20)
将所有满足特定条件的值替换为另一个值
(algorithm function object)
ranges::replace_copy
ranges::replace_copy_if
(C++20)
(C++20)
复制一个范围,将满足特定条件的元素替换为另一个值
(algorithm function object)
ranges::swap_ranges
(C++20)
交换两个元素范围
(algorithm function object)
ranges::reverse
(C++20)
反转范围中元素的顺序
(algorithm function object)
ranges::reverse_copy
(C++20)
创建一个反转的范围副本
(algorithm function object)
ranges::rotate
(C++20)
旋转范围中元素的顺序
(algorithm function object)
ranges::rotate_copy
(C++20)
复制并旋转元素范围
(algorithm function object)
ranges::shift_left
ranges::shift_right
(C++23)
移动范围中的元素
(algorithm function object)
ranges::sample
(C++20)
从序列中选择 N 个随机元素
(algorithm function object)
ranges::shuffle
(C++20)
随机重新排序范围中的元素
(algorithm function object)
ranges::unique
(C++20)
移除范围中连续重复的元素
(algorithm function object)
ranges::unique_copy
(C++20)
创建某个元素范围的副本,其中不包含连续重复项
(algorithm function object)
分区操作
ranges::is_partitioned
(C++20)
确定范围是否由给定谓词分区
(algorithm function object)
ranges::partition
(C++20)
将元素范围划分为两组
(algorithm function object)
ranges::partition_copy
(C++20)
复制一个范围,将元素划分为两组
(algorithm function object)
ranges::stable_partition
(C++20)
将元素划分为两组,同时保持其相对顺序
(algorithm function object)
ranges::partition_point
(C++20)
定位已分区范围的分区点
(algorithm function object)
排序操作
ranges::is_sorted
(C++20)
检查范围是否已排序为升序
(algorithm function object)
ranges::is_sorted_until
(C++20)
查找最大的已排序子范围
(algorithm function object)
ranges::sort
(C++20)
将范围排序为升序
(algorithm function object)
ranges::partial_sort
(C++20)
对范围的前 N 个元素进行排序
(algorithm function object)
ranges::partial_sort_copy
(C++20)
复制并部分排序元素范围
(algorithm function object)
ranges::stable_sort
(C++20)
排序元素范围,同时保持相等元素之间的顺序
(algorithm function object)
ranges::nth_element
(C++20)
部分排序给定范围,确保它按给定元素分区
(algorithm function object)
二分搜索操作 (在已排序范围上)
ranges::lower_bound
(C++20)
返回指向第一个不小于给定值的元素的迭代器
(algorithm function object)
ranges::upper_bound
(C++20)
返回指向首个大于某值的元素的迭代器
(algorithm function object)
ranges::binary_search
(C++20)
确定元素是否存在于部分有序的范围内
(algorithm function object)
ranges::equal_range
(C++20)
返回与特定键匹配的元素范围
(algorithm function object)
其他排序范围上的操作
ranges::merge
(C++20)
合并两个已排序的范围
(algorithm function object)
ranges::inplace_merge
(C++20)
就地合并两个有序范围
(algorithm function object)
集合操作(在已排序的范围上)
ranges::includes
(C++20)
如果一个序列是另一个序列的子序列,则返回 true
(algorithm function object)
ranges::set_difference
(C++20)
计算两个集合的差集
(algorithm function object)
ranges::set_intersection
(C++20)
计算两个集合的交集
(algorithm function object)
ranges::set_symmetric_difference
(C++20)
计算两个集合的对称差集
(algorithm function object)
ranges::set_union
(C++20)
计算两个集合的并集
(algorithm function object)
堆操作
ranges::is_heap
(C++20)
检查给定范围是否为最大堆
(algorithm function object)
ranges::is_heap_until
(C++20)
查找作为最大堆的最大子范围
(algorithm function object)
ranges::make_heap
(C++20)
从元素范围创建最大堆
(algorithm function object)
ranges::push_heap
(C++20)
向最大堆添加元素
(algorithm function object)
ranges::pop_heap
(C++20)
从最大堆中移除最大的元素
(algorithm function object)
ranges::sort_heap
(C++20)
将最大堆转换为升序排序的元素范围
(algorithm function object)
最小值/最大值操作
ranges::max
(C++20)
返回给定值中较大的那个
(algorithm function object)
ranges::max_element
(C++20)
返回范围中最大的元素
(algorithm function object)
ranges::min
(C++20)
返回给定值中较小的那个
(algorithm function object)
ranges::min_element
(C++20)
返回范围中最小的元素
(algorithm function object)
ranges::minmax
(C++20)
返回两个元素中较小和较大的那个
(algorithm function object)
ranges::minmax_element
(C++20)
返回范围中最小和最大的元素
(algorithm function object)
ranges::clamp
(C++20)
将值限制在边界值对之间
(algorithm function object)
比较操作
ranges::equal
(C++20)
确定两组元素是否相同
(algorithm function object)
ranges::lexicographical_compare
(C++20)
如果一个范围在字典序上小于另一个范围,则返回 true
(算法函数对象)
排列操作
ranges::is_permutation
(C++20)
确定一个序列是否是另一个序列的排列
(算法函数对象)
ranges::next_permutation
(C++20)
生成元素范围的下一个更大的字典序排列
(算法函数对象)
ranges::prev_permutation
(C++20)
生成元素范围的下一个更小的字典序排列
(算法函数对象)
概要
#include <initializer_list>
namespace std {
namespace ranges {
// algorithm result types
template<class I, class F>
struct in_fun_result;
template<class I1, class I2>
struct in_in_result;
template<class I, class O>
struct in_out_result;
template<class I1, class I2, class O>
struct in_in_out_result;
template<class I, class O1, class O2>
struct in_out_out_result;
template<class T>
struct min_max_result;
template<class I>
struct in_found_result;
template<class I, class T>
struct in_value_result;
template<class O, class T>
struct out_value_result;
}
// non-modifying sequence operations
// all of
template<class InputIter, class Pred>
constexpr bool all_of(InputIter first, InputIter last, Pred pred);
template<class ExecutionPolicy, class ForwardIter, class Pred>
bool all_of(ExecutionPolicy&& exec,
ForwardIter first, ForwardIter last, Pred pred);
namespace ranges {
template<input_iterator I, sentinel_for<I> S, class Proj = identity,
indirect_unary_predicate<projected<I, Proj>> Pred>
constexpr bool all_of(I first, S last, Pred pred, Proj proj = {});
template<input_range R, class Proj = identity,
indirect_unary_predicate<projected<iterator_t<R>, Proj>> Pred>
constexpr bool all_of(R&& r, Pred pred, Proj proj = {});
}
// any of
template<class InputIter, class Pred>
constexpr bool any_of(InputIter first, InputIter last, Pred pred);
template<class ExecutionPolicy, class ForwardIter, class Pred>
bool any_of(ExecutionPolicy&& exec,
ForwardIter first, ForwardIter last, Pred pred);
namespace ranges {
template<input_iterator I, sentinel_for<I> S, class Proj = identity,
indirect_unary_predicate<projected<I, Proj>> Pred>
constexpr bool any_of(I first, S last, Pred pred, Proj proj = {});
template<input_range R, class Proj = identity,
indirect_unary_predicate<projected<iterator_t<R>, Proj>> Pred>
constexpr bool any_of(R&& r, Pred pred, Proj proj = {});
}
// none of
template<class InputIter, class Pred>
constexpr bool none_of(InputIter first, InputIter last, Pred pred);
template<class ExecutionPolicy, class ForwardIter, class Pred>
bool none_of(ExecutionPolicy&& exec,
ForwardIter first, ForwardIter last, Pred pred);
namespace ranges {
template<input_iterator I, sentinel_for<I> S, class Proj = identity,
indirect_unary_predicate<projected<I, Proj>> Pred>
constexpr bool none_of(I first, S last, Pred pred, Proj proj = {});
template<input_range R, class Proj = identity,
indirect_unary_predicate<projected<iterator_t<R>, Proj>> Pred>
constexpr bool none_of(R&& r, Pred pred, Proj proj = {});
}
// contains
namespace ranges {
template<input_iterator I, sentinel_for<I> S, class Proj = identity,
class T = projected_value_t<I, Proj>>
requires indirect_binary_predicate<ranges::equal_to, projected<I, Proj>, const T*>
constexpr bool contains(I first, S last, const T& value, Proj proj = {});
template<input_range R, class Proj = identity,
class T = projected_value_t<iterator_t<R>, Proj>>
requires indirect_binary_predicate<ranges::equal_to,
projected<iterator_t<R>, Proj>, const T*>
constexpr bool contains(R&& r, const T& value, Proj proj = {});
template<forward_iterator I1, sentinel_for<I1> S1,
forward_iterator I2, sentinel_for<I2> S2,
class Pred = ranges::equal_to, class Proj1 = identity,
class Proj2 = identity>
requires indirectly_comparable<I1, I2, Pred, Proj1, Proj2>
constexpr bool contains_subrange(I1 first1, S1 last1, I2 first2, S2 last2,
Pred pred = {}, Proj1 proj1 = {},
Proj2 proj2 = {});
template<forward_range R1, forward_range R2,
class Pred = ranges::equal_to, class Proj1 = identity,
class Proj2 = identity>
requires indirectly_comparable<iterator_t<R1>, iterator_t<R2>, Pred, Proj1, Proj2>
constexpr bool contains_subrange(R1&& r1, R2&& r2,
Pred pred = {}, Proj1 proj1 = {},
Proj2 proj2 = {});
}
// for each
template<class InputIter, class Function>
constexpr Function for_each(InputIter first, InputIter last, Function f);
template<class ExecutionPolicy, class ForwardIter, class Function>
void for_each(ExecutionPolicy&& exec,
ForwardIter first, ForwardIter last, Function f);
namespace ranges {
template<class I, class F>
using for_each_result = in_fun_result<I, F>;
template<input_iterator I, sentinel_for<I> S, class Proj = identity,
indirectly_unary_invocable<projected<I, Proj>> Fun>
constexpr for_each_result<I, Fun>
for_each(I first, S last, Fun f, Proj proj = {});
template<input_range R, class Proj = identity,
indirectly_unary_invocable<projected<iterator_t<R>, Proj>> Fun>
constexpr for_each_result<borrowed_iterator_t<R>, Fun>
for_each(R&& r, Fun f, Proj proj = {});
}
template<class InputIter, class Size, class Function>
constexpr InputIter for_each_n(InputIter first, Size n, Function f);
template<class ExecutionPolicy, class ForwardIter, class Size, class Function>
ForwardIter for_each_n(ExecutionPolicy&& exec,
ForwardIter first, Size n, Function f);
namespace ranges {
template<class I, class F>
using for_each_n_result = in_fun_result<I, F>;
template<input_iterator I, class Proj = identity,
indirectly_unary_invocable<projected<I, Proj>> Fun>
constexpr for_each_n_result<I, Fun>
for_each_n(I first, iter_difference_t<I> n, Fun f, Proj proj = {});
}
// find
template<class InputIter, class T = typename iterator_traits<InputIter>::value_type>
constexpr InputIter find(InputIter first, InputIter last, const T& value);
template<class ExecutionPolicy, class ForwardIter,
class T = typename iterator_traits<InputIter>::value_type>
ForwardIter find(ExecutionPolicy&& exec,
ForwardIter first, ForwardIter last, const T& value);
template<class InputIter, class Pred>
constexpr InputIter find_if(InputIter first, InputIter last, Pred pred);
template<class ExecutionPolicy, class ForwardIter, class Pred>
ForwardIter find_if(ExecutionPolicy&& exec,
ForwardIter first, ForwardIter last, Pred pred);
template<class InputIter, class Pred>
constexpr InputIter find_if_not(InputIter first, InputIter last, Pred pred);
template<class ExecutionPolicy, class ForwardIter, class Pred>
ForwardIter find_if_not(ExecutionPolicy&& exec,
ForwardIter first, ForwardIter last, Pred pred);
namespace ranges {
template<input_iterator I, sentinel_for<I> S, class Proj = identity
class T = projected_value_t<I, Proj>>
requires indirect_binary_predicate<ranges::equal_to, projected<I, Proj>, const T*>
constexpr I find(I first, S last, const T& value, Proj proj = {});
template<input_range R, class Proj = identity,
class T = projected_value_t<iterator_t<R>, Proj>>
requires indirect_binary_predicate<ranges::equal_to,
projected<iterator_t<R>, Proj>, const T*>
constexpr borrowed_iterator_t<R>
find(R&& r, const T& value, Proj proj = {});
template<input_iterator I, sentinel_for<I> S, class Proj = identity,
indirect_unary_predicate<projected<I, Proj>> Pred>
constexpr I find_if(I first, S last, Pred pred, Proj proj = {});
template<input_range R, class Proj = identity,
indirect_unary_predicate<projected<iterator_t<R>, Proj>> Pred>
constexpr borrowed_iterator_t<R>
find_if(R&& r, Pred pred, Proj proj = {});
template<input_iterator I, sentinel_for<I> S, class Proj = identity,
indirect_unary_predicate<projected<I, Proj>> Pred>
constexpr I find_if_not(I first, S last, Pred pred, Proj proj = {});
template<input_range R, class Proj = identity,
indirect_unary_predicate<projected<iterator_t<R>, Proj>> Pred>
constexpr borrowed_iterator_t<R>
find_if_not(R&& r, Pred pred, Proj proj = {});
}
// find last
namespace ranges {
template<forward_iterator I, sentinel_for<I> S, class T, class Proj = identity>
requires indirect_binary_predicate<ranges::equal_to, projected<I, Proj>, const T*>
constexpr subrange<I> find_last(I first, S last, const T& value, Proj proj = {});
template<forward_range R, class T, class Proj = identity>
requires
indirect_binary_predicate<ranges::equal_to,
projected<iterator_t<R>, Proj>, const T*>
constexpr borrowed_subrange_t<R> find_last(R&& r, const T& value, Proj proj = {});
template<forward_iterator I, sentinel_for<I> S, class Proj = identity,
indirect_unary_predicate<projected<I, Proj>> Pred>
constexpr subrange<I> find_last_if(I first, S last, Pred pred, Proj proj = {});
template<forward_range R, class Proj = identity,
indirect_unary_predicate<projected<iterator_t<R>, Proj>> Pred>
constexpr borrowed_subrange_t<R> find_last_if(R&& r, Pred pred, Proj proj = {});
template<forward_iterator I, sentinel_for<I> S, class Proj = identity,
indirect_unary_predicate<projected<I, Proj>> Pred>
constexpr subrange<I> find_last_if_not(I first, S last, Pred pred, Proj proj = {});
template<forward_range R, class Proj = identity,
indirect_unary_predicate<projected<iterator_t<R>, Proj>> Pred>
constexpr borrowed_subrange_t<R> find_last_if_not(R&& r, Pred pred, Proj proj = {});
}
// find end
template<class ForwardIter1, class ForwardIter2>
constexpr ForwardIter1
find_end(ForwardIter1 first1, ForwardIter1 last1,
ForwardIter2 first2, ForwardIter2 last2);
template<class ForwardIter1, class ForwardIter2, class BinaryPred>
constexpr ForwardIter1
find_end(ForwardIter1 first1, ForwardIter1 last1,
ForwardIter2 first2, ForwardIter2 last2,
BinaryPred pred);
template<class ExecutionPolicy, class ForwardIter1, class ForwardIter2>
ForwardIter1
find_end(ExecutionPolicy&& exec,
ForwardIter1 first1, ForwardIter1 last1,
ForwardIter2 first2, ForwardIter2 last2);
template<class ExecutionPolicy, class ForwardIter1,
class ForwardIter2, class BinaryPred>
ForwardIter1
find_end(ExecutionPolicy&& exec,
ForwardIter1 first1, ForwardIter1 last1,
ForwardIter2 first2, ForwardIter2 last2,
BinaryPred pred);
namespace ranges {
template<forward_iterator I1, sentinel_for<I1> S1, forward_iterator I2,
sentinel_for<I2> S2, class Pred = ranges::equal_to,
class Proj1 = identity, class Proj2 = identity>
requires indirectly_comparable<I1, I2, Pred, Proj1, Proj2>
constexpr subrange<I1>
find_end(I1 first1, S1 last1, I2 first2, S2 last2, Pred pred = {},
Proj1 proj1 = {}, Proj2 proj2 = {});
template<forward_range R1, forward_range R2, class Pred = ranges::equal_to,
class Proj1 = identity, class Proj2 = identity>
requires indirectly_comparable<iterator_t<R1>, iterator_t<R2>, Pred, Proj1, Proj2>
constexpr borrowed_subrange_t<R1>
find_end(R1&& r1, R2&& r2, Pred pred = {},
Proj1 proj1 = {}, Proj2 proj2 = {});
}
// find first
template<class InputIter, class ForwardIter>
constexpr InputIter
find_first_of(InputIter first1, InputIter last1,
ForwardIter first2, ForwardIter last2);
template<class InputIter, class ForwardIter, class BinaryPred>
constexpr InputIter
find_first_of(InputIter first1, InputIter last1,
ForwardIter first2, ForwardIter last2,
BinaryPred pred);
template<class ExecutionPolicy, class ForwardIter1, class ForwardIter2>
ForwardIter1
find_first_of(ExecutionPolicy&& exec,
ForwardIter1 first1, ForwardIter1 last1,
ForwardIter2 first2, ForwardIter2 last2);
template<class ExecutionPolicy, class ForwardIter1,
class ForwardIter2, class BinaryPred>
ForwardIter1
find_first_of(ExecutionPolicy&& exec,
ForwardIter1 first1, ForwardIter1 last1,
ForwardIter2 first2, ForwardIter2 last2,
BinaryPred pred);
namespace ranges {
template<input_iterator I1, sentinel_for<I1> S1, forward_iterator I2,
sentinel_for<I2> S2, class Pred = ranges::equal_to,
class Proj1 = identity, class Proj2 = identity>
requires indirectly_comparable<I1, I2, Pred, Proj1, Proj2>
constexpr I1 find_first_of(I1 first1, S1 last1, I2 first2, S2 last2, Pred pred = {},
Proj1 proj1 = {}, Proj2 proj2 = {});
template<input_range R1, forward_range R2, class Pred = ranges::equal_to,
class Proj1 = identity, class Proj2 = identity>
requires indirectly_comparable<iterator_t<R1>, iterator_t<R2>, Pred, Proj1, Proj2>
constexpr borrowed_iterator_t<R1>
find_first_of(R1&& r1, R2&& r2, Pred pred = {},
Proj1 proj1 = {}, Proj2 proj2 = {});
}
// adjacent find
template<class ForwardIter>
constexpr ForwardIter adjacent_find(ForwardIter first, ForwardIter last);
template<class ForwardIter, class BinaryPred>
constexpr ForwardIter adjacent_find(ForwardIter first, ForwardIter last,
BinaryPred pred);
template<class ExecutionPolicy, class ForwardIter>
ForwardIter adjacent_find(ExecutionPolicy&& exec,
ForwardIter first, ForwardIter last);
template<class ExecutionPolicy, class ForwardIter, class BinaryPred>
ForwardIter adjacent_find(ExecutionPolicy&& exec,
ForwardIter first, ForwardIter last, BinaryPred pred);
namespace ranges {
template<forward_iterator I, sentinel_for<I> S, class Proj = identity,
indirect_binary_predicate<projected<I, Proj>,
projected<I, Proj>> Pred = ranges::equal_to>
constexpr I adjacent_find(I first, S last, Pred pred = {}, Proj proj = {});
template<forward_range R, class Proj = identity,
indirect_binary_predicate<projected<iterator_t<R>, Proj>,
projected<iterator_t<R>, Proj>>
Pred = ranges::equal_to>
constexpr borrowed_iterator_t<R>
adjacent_find(R&& r, Pred pred = {}, Proj proj = {});
}
// count
template<class InputIter, class T = typename iterator_traits<InputIter>::value_type>
constexpr typename iterator_traits<InputIter>::difference_type
count(InputIter first, InputIter last, const T& value);
template<class ExecutionPolicy, class ForwardIter,
class T = typename iterator_traits<InputIterator>::value_type>
typename iterator_traits<ForwardIter>::difference_type
count(ExecutionPolicy&& exec,
ForwardIter first, ForwardIter last, const T& value);
template<class InputIter, class Pred>
constexpr typename iterator_traits<InputIter>::difference_type
count_if(InputIter first, InputIter last, Pred pred);
template<class ExecutionPolicy, class ForwardIter, class Pred>
typename iterator_traits<ForwardIter>::difference_type
count_if(ExecutionPolicy&& exec,
ForwardIter first, ForwardIter last, Pred pred);
namespace ranges {
template<input_iterator I, sentinel_for<I> S, class Proj = identity,
class T = projected_value_t<I, Proj>>
requires indirect_binary_predicate<ranges::equal_to, projected<I, Proj>, const T*>
constexpr iter_difference_t<I>
count(I first, S last, const T& value, Proj proj = {});
template<input_range R, class Proj = identity,
class T = projected_value_t<iterator_t<R>, Proj>>
requires indirect_binary_predicate<ranges::equal_to,
projected<iterator_t<R>, Proj>, const T*>
constexpr range_difference_t<R>
count(R&& r, const T& value, Proj proj = {});
template<input_iterator I, sentinel_for<I> S, class Proj = identity,
indirect_unary_predicate<projected<I, Proj>> Pred>
constexpr iter_difference_t<I>
count_if(I first, S last, Pred pred, Proj proj = {});
template<input_range R, class Proj = identity,
indirect_unary_predicate<projected<iterator_t<R>, Proj>> Pred>
constexpr range_difference_t<R>
count_if(R&& r, Pred pred, Proj proj = {});
}
// mismatch
template<class InputIter1, class InputIter2>
constexpr pair<InputIter1, InputIter2>
mismatch(InputIter1 first1, InputIter1 last1,
InputIter2 first2);
template<class InputIter1, class InputIter2, class BinaryPred>
constexpr pair<InputIter1, InputIter2>
mismatch(InputIter1 first1, InputIter1 last1,
InputIter2 first2, BinaryPred pred);
template<class InputIter1, class InputIter2>
constexpr pair<InputIter1, InputIter2>
mismatch(InputIter1 first1, InputIter1 last1,
InputIter2 first2, InputIter2 last2);
template<class InputIter1, class InputIter2, class BinaryPred>
constexpr pair<InputIter1, InputIter2>
mismatch(InputIter1 first1, InputIter1 last1,
InputIter2 first2, InputIter2 last2,
BinaryPred pred);
template<class ExecutionPolicy, class ForwardIter1, class ForwardIter2>
pair<ForwardIter1, ForwardIter2>
mismatch(ExecutionPolicy&& exec,
ForwardIter1 first1, ForwardIter1 last1,
ForwardIter2 first2);
template<class ExecutionPolicy, class ForwardIter1, class ForwardIter2,
class BinaryPred>
pair<ForwardIter1, ForwardIter2>
mismatch(ExecutionPolicy&& exec,
ForwardIter1 first1, ForwardIter1 last1,
ForwardIter2 first2, BinaryPred pred);
template<class ExecutionPolicy, class ForwardIter1, class ForwardIter2>
pair<ForwardIter1, ForwardIter2>
mismatch(ExecutionPolicy&& exec,
ForwardIter1 first1, ForwardIter1 last1,
ForwardIter2 first2, ForwardIter2 last2);
template<class ExecutionPolicy, class ForwardIter1, class ForwardIter2,
class BinaryPred>
pair<ForwardIter1, ForwardIter2>
mismatch(ExecutionPolicy&& exec,
ForwardIter1 first1, ForwardIter1 last1,
ForwardIter2 first2, ForwardIter2 last2,
BinaryPred pred);
namespace ranges {
template<class I1, class I2>
using mismatch_result = in_in_result<I1, I2>;
template<input_iterator I1, sentinel_for<I1> S1, input_iterator I2,
sentinel_for<I2> S2, class Pred = ranges::equal_to, class Proj1 = identity,
class Proj2 = identity>
requires indirectly_comparable<I1, I2, Pred, Proj1, Proj2>
constexpr mismatch_result<I1, I2>
mismatch(I1 first1, S1 last1, I2 first2, S2 last2, Pred pred = {},
Proj1 proj1 = {}, Proj2 proj2 = {});
template<input_range R1, input_range R2,
class Pred = ranges::equal_to, class Proj1 = identity,
class Proj2 = identity>
requires indirectly_comparable<iterator_t<R1>, iterator_t<R2>, Pred, Proj1, Proj2>
constexpr mismatch_result<borrowed_iterator_t<R1>, borrowed_iterator_t<R2>>
mismatch(R1&& r1, R2&& r2, Pred pred = {},
Proj1 proj1 = {}, Proj2 proj2 = {});
}
// equal
template<class InputIter1, class InputIter2>
constexpr bool equal(InputIter1 first1, InputIter1 last1,
InputIter2 first2);
template<class InputIter1, class InputIter2, class BinaryPred>
constexpr bool equal(InputIter1 first1, InputIter1 last1,
InputIter2 first2, BinaryPred pred);
template<class InputIter1, class InputIter2>
constexpr bool equal(InputIter1 first1, InputIter1 last1,
InputIter2 first2, InputIter2 last2);
template<class InputIter1, class InputIter2, class BinaryPred>
constexpr bool equal(InputIter1 first1, InputIter1 last1,
InputIter2 first2, InputIter2 last2,
BinaryPred pred);
template<class ExecutionPolicy, class ForwardIter1, class ForwardIter2>
bool equal(ExecutionPolicy&& exec,
ForwardIter1 first1, ForwardIter1 last1,
ForwardIter2 first2);
template<class ExecutionPolicy, class ForwardIter1, class ForwardIter2,
class BinaryPred>
bool equal(ExecutionPolicy&& exec,
ForwardIter1 first1, ForwardIter1 last1,
ForwardIter2 first2, BinaryPred pred);
template<class ExecutionPolicy, class ForwardIter1, class ForwardIter2>
bool equal(ExecutionPolicy&& exec,
ForwardIter1 first1, ForwardIter1 last1,
ForwardIter2 first2, ForwardIter2 last2);
template<class ExecutionPolicy, class ForwardIter1, class ForwardIter2,
class BinaryPred>
bool equal(ExecutionPolicy&& exec,
ForwardIter1 first1, ForwardIter1 last1,
ForwardIter2 first2, ForwardIter2 last2,
BinaryPred pred);
namespace ranges {
template<input_iterator I1, sentinel_for<I1> S1, input_iterator I2,
sentinel_for<I2> S2, class Pred = ranges::equal_to, class Proj1 = identity,
class Proj2 = identity>
requires indirectly_comparable<I1, I2, Pred, Proj1, Proj2>
constexpr bool equal(I1 first1, S1 last1, I2 first2, S2 last2,
Pred pred = {},
Proj1 proj1 = {}, Proj2 proj2 = {});
template<input_range R1, input_range R2, class Pred = ranges::equal_to,
class Proj1 = identity, class Proj2 = identity>
requires indirectly_comparable<iterator_t<R1>, iterator_t<R2>, Pred, Proj1, Proj2>
constexpr bool equal(R1&& r1, R2&& r2, Pred pred = {},
Proj1 proj1 = {}, Proj2 proj2 = {});
}
// is permutation
template<class ForwardIter1, class ForwardIter2>
constexpr bool is_permutation(ForwardIter1 first1, ForwardIter1 last1,
ForwardIter2 first2);
template<class ForwardIter1, class ForwardIter2, class BinaryPred>
constexpr bool is_permutation(ForwardIter1 first1, ForwardIter1 last1,
ForwardIter2 first2, BinaryPred pred);
template<class ForwardIter1, class ForwardIter2>
constexpr bool is_permutation(ForwardIter1 first1, ForwardIter1 last1,
ForwardIter2 first2, ForwardIter2 last2);
template<class ForwardIter1, class ForwardIter2, class BinaryPred>
constexpr bool is_permutation(ForwardIter1 first1, ForwardIter1 last1,
ForwardIter2 first2, ForwardIter2 last2,
BinaryPred pred);
namespace ranges {
template<forward_iterator I1, sentinel_for<I1> S1, forward_iterator I2,
sentinel_for<I2> S2, class Proj1 = identity, class Proj2 = identity,
indirect_equivalence_relation<projected<I1, Proj1>,
projected<I2, Proj2>> Pred = ranges::equal_to>
constexpr bool is_permutation(I1 first1, S1 last1, I2 first2, S2 last2,
Pred pred = {},
Proj1 proj1 = {}, Proj2 proj2 = {});
template<forward_range R1, forward_range R2,
class Proj1 = identity, class Proj2 = identity,
indirect_equivalence_relation<projected<iterator_t<R1>, Proj1>,
projected<iterator_t<R2>, Proj2>>
Pred = ranges::equal_to>
constexpr bool is_permutation(R1&& r1, R2&& r2, Pred pred = {},
Proj1 proj1 = {}, Proj2 proj2 = {});
}
// search
template<class ForwardIter1, class ForwardIter2>
constexpr ForwardIter1
search(ForwardIter1 first1, ForwardIter1 last1,
ForwardIter2 first2, ForwardIter2 last2);
template<class ForwardIter1, class ForwardIter2, class BinaryPred>
constexpr ForwardIter1
search(ForwardIter1 first1, ForwardIter1 last1,
ForwardIter2 first2, ForwardIter2 last2, BinaryPred pred);
template<class ExecutionPolicy, class ForwardIter1, class ForwardIter2>
ForwardIter1
search(ExecutionPolicy&& exec,
ForwardIter1 first1, ForwardIter1 last1,
ForwardIter2 first2, ForwardIter2 last2);
template<class ExecutionPolicy, class ForwardIter1, class ForwardIter2,
class BinaryPred>
ForwardIter1
search(ExecutionPolicy&& exec,
ForwardIter1 first1, ForwardIter1 last1,
ForwardIter2 first2, ForwardIter2 last2, BinaryPred pred);
namespace ranges {
template<forward_iterator I1, sentinel_for<I1> S1, forward_iterator I2,
sentinel_for<I2> S2, class Pred = ranges::equal_to,
class Proj1 = identity, class Proj2 = identity>
requires indirectly_comparable<I1, I2, Pred, Proj1, Proj2>
constexpr subrange<I1>
search(I1 first1, S1 last1, I2 first2, S2 last2, Pred pred = {},
Proj1 proj1 = {}, Proj2 proj2 = {});
template<forward_range R1, forward_range R2, class Pred = ranges::equal_to,
class Proj1 = identity, class Proj2 = identity>
requires indirectly_comparable<iterator_t<R1>, iterator_t<R2>, Pred, Proj1, Proj2>
constexpr borrowed_subrange_t<R1>
search(R1&& r1, R2&& r2, Pred pred = {},
Proj1 proj1 = {}, Proj2 proj2 = {});
}
template<class ForwardIter, class Size,
class T = typename iterator_traits<ForwardIter>::value_type>
constexpr ForwardIter
search_n(ForwardIter first, ForwardIter last,
Size count, const T& value);
template<class ForwardIter, class Size,
class T = typename iterator_traits<ForwardIter>::value_type, class BinaryPred>
constexpr ForwardIter
search_n(ForwardIter first, ForwardIter last,
Size count, const T& value, BinaryPred pred);
template<class ExecutionPolicy, class ForwardIter, class Size,
class T = typename iterator_traits<ForwardIter>::value_type>
ForwardIter
search_n(ExecutionPolicy&& exec,
ForwardIter first, ForwardIter last,
Size count, const T& value);
template<class ExecutionPolicy, class ForwardIter, class Size,
class T = typename iterator_traits<ForwardIter>::value_type, class BinaryPred>
ForwardIter
search_n(ExecutionPolicy&& exec,
ForwardIter first, ForwardIter last,
Size count, const T& value, BinaryPred pred);
namespace ranges {
template<forward_iterator I, sentinel_for<I> S,
class Pred = ranges::equal_to, class Proj = identity,
class T = projected_value_t<I, Proj>>
requires indirectly_comparable<I, const T*, Pred, Proj>
constexpr subrange<I>
search_n(I first, S last, iter_difference_t<I> count,
const T& value, Pred pred = {}, Proj proj = {});
template<forward_range R, class Pred = ranges::equal_to, class Proj = identity,
projected_value_t<iterator_t<R>, Proj>>
requires indirectly_comparable<iterator_t<R>, const T*, Pred, Proj>
constexpr borrowed_subrange_t<R>
search_n(R&& r, range_difference_t<R> count,
const T& value, Pred pred = {}, Proj proj = {});
}
template<class ForwardIter, class Searcher>
constexpr ForwardIter
search(ForwardIter first, ForwardIter last, const Searcher& searcher);
namespace ranges {
// starts with
template<input_iterator I1, sentinel_for<I1> S1, input_iterator I2,
sentinel_for<I2> S2, class Pred = ranges::equal_to,
class Proj1 = identity, class Proj2 = identity>
requires indirectly_comparable<I1, I2, Pred, Proj1, Proj2>
constexpr bool starts_with(I1 first1, S1 last1, I2 first2, S2 last2, Pred pred = {},
Proj1 proj1 = {}, Proj2 proj2 = {});
template<input_range R1, input_range R2, class Pred = ranges::equal_to,
class Proj1 = identity, class Proj2 = identity>
requires indirectly_comparable<iterator_t<R1>, iterator_t<R2>, Pred, Proj1, Proj2>
constexpr bool starts_with(R1&& r1, R2&& r2, Pred pred = {},
Proj1 proj1 = {}, Proj2 proj2 = {});
// ends with
template<input_iterator I1, sentinel_for<I1> S1, input_iterator I2,
sentinel_for<I2> S2, class Pred = ranges::equal_to,
class Proj1 = identity, class Proj2 = identity>
requires (forward_iterator<I1> || sized_sentinel_for<S1, I1>) &&
(forward_iterator<I2> || sized_sentinel_for<S2, I2>) &&
indirectly_comparable<I1, I2, Pred, Proj1, Proj2>
constexpr bool ends_with(I1 first1, S1 last1, I2 first2, S2 last2, Pred pred = {},
Proj1 proj1 = {}, Proj2 proj2 = {});
template<input_range R1, input_range R2, class Pred = ranges::equal_to,
class Proj1 = identity, class Proj2 = identity>
requires (forward_range<R1> || sized_range<R1>) &&
(forward_range<R2> || sized_range<R2>) &&
indirectly_comparable<iterator_t<R1>, iterator_t<R2>, Pred, Proj1, Proj2>
constexpr bool ends_with(R1&& r1, R2&& r2, Pred pred = {},
Proj1 proj1 = {}, Proj2 proj2 = {});
// fold
template<class F>
class /* flipped */ { // exposition only
F f; // exposition only
public:
template<class T, class U> requires invocable<F&, U, T>
invoke_result_t<F&, U, T> operator()(T&&, U&&);
};
template<class F, class T, class I, class U>
concept /* indirectly-binary-left-foldable-impl */ = // exposition only
movable<T> && movable<U> &&
convertible_to<T, U> && invocable<F&, U, iter_reference_t<I>> &&
assignable_from<U&, invoke_result_t<F&, U, iter_reference_t<I>>>;
template<class F, class T, class I>
concept /* indirectly-binary-left-foldable */ = // exposition only
copy_constructible<F> && indirectly_readable<I> &&
invocable<F&, T, iter_reference_t<I>> &&
convertible_to<invoke_result_t<F&, T, iter_reference_t<I>>,
decay_t<invoke_result_t<F&, T, iter_reference_t<I>>>> &&
/* indirectly-binary-left-foldable-impl */
<F, T, I, decay_t<invoke_result_t<F&, T, iter_reference_t<I>>>>;
template<class F, class T, class I>
concept /* indirectly-binary-right-foldable */ = // exposition only
/* indirectly-binary-left-foldable */</* flipped */<F>, T, I>;
template<input_iterator I, sentinel_for<I> S, class T = iter_value_t<I>,
/* indirectly-binary-left-foldable */<T, I> F>
constexpr auto fold_left(I first, S last, T init, F f);
template<input_range R, class T = range_value_t<R>,
/* indirectly-binary-left-foldable */<T, iterator_t<R>> F>
constexpr auto fold_left(R&& r, T init, F f);
template<input_iterator I, sentinel_for<I> S,
/* indirectly-binary-left-foldable */<iter_value_t<I>, I> F>
requires constructible_from<iter_value_t<I>, iter_reference_t<I>>
constexpr auto fold_left_first(I first, S last, F f);
template<input_range R,
/* indirectly-binary-left-foldable */<range_value_t<R>, iterator_t<R>> F>
requires constructible_from<range_value_t<R>, range_reference_t<R>>
constexpr auto fold_left_first(R&& r, F f);
template<bidirectional_iterator I, sentinel_for<I> S, class T = iter_value_t<I>,
/* indirectly-binary-right-foldable */<T, I> F>
constexpr auto fold_right(I first, S last, T init, F f);
template<bidirectional_range R, class T = range_value_t<R>,
/* indirectly-binary-right-foldable */<T, iterator_t<R>> F>
constexpr auto fold_right(R&& r, T init, F f);
template<bidirectional_iterator I, sentinel_for<I> S,
/* indirectly-binary-right-foldable */<iter_value_t<I>, I> F>
requires constructible_from<iter_value_t<I>, iter_reference_t<I>>
constexpr auto fold_right_last(I first, S last, F f);
template<bidirectional_range R,
/* indirectly-binary-right-foldable */<range_value_t<R>, iterator_t<R>> F>
requires constructible_from<range_value_t<R>, range_reference_t<R>>
constexpr auto fold_right_last(R&& r, F f);
template<class I, class T>
using fold_left_with_iter_result = in_value_result<I, T>;
template<class I, class T>
using fold_left_first_with_iter_result = in_value_result<I, T>;
template<input_iterator I, sentinel_for<I> S, class T = iter_value_t<I>,
/* indirectly-binary-left-foldable */<T, I> F>
constexpr /* see description */ fold_left_with_iter(I first, S last, T init, F f);
template<input_range R, class T = range_value_t<R>,
/* indirectly-binary-left-foldable */<T, iterator_t<R>> F>
constexpr /* see description */ fold_left_with_iter(R&& r, T init, F f);
template<input_iterator I, sentinel_for<I> S,
/* indirectly-binary-left-foldable */<iter_value_t<I>, I> F>
requires constructible_from<iter_value_t<I>, iter_reference_t<I>>
constexpr /* see description */ fold_left_first_with_iter(I first, S last, F f);
template<input_range R,
/* indirectly-binary-left-foldable */<range_value_t<R>, iterator_t<R>> F>
requires constructible_from<range_value_t<R>, range_reference_t<R>>
constexpr /* see description */ fold_left_first_with_iter(R&& r, F f);
}
// mutating sequence operations
// copy
template<class InputIter, class OutputIter>
constexpr OutputIter copy(InputIter first, InputIter last,
OutputIter result);
template<class ExecutionPolicy, class ForwardIter1, class ForwardIter2>
ForwardIter2 copy(ExecutionPolicy&& exec,
ForwardIter1 first, ForwardIter1 last,
ForwardIter2 result);
namespace ranges {
template<class I, class O>
using copy_result = in_out_result<I, O>;
template<input_iterator I, sentinel_for<I> S, weakly_incrementable O>
requires indirectly_copyable<I, O>
constexpr copy_result<I, O> copy(I first, S last, O result);
template<input_range R, weakly_incrementable O>
requires indirectly_copyable<iterator_t<R>, O>
constexpr copy_result<borrowed_iterator_t<R>, O> copy(R&& r, O result);
}
template<class InputIter, class Size, class OutputIter>
constexpr OutputIter copy_n(InputIter first, Size n, OutputIter result);
template<class ExecutionPolicy,
class ForwardIter1, class Size, class ForwardIter2>
ForwardIter2 copy_n(ExecutionPolicy&& exec,
ForwardIter1 first, Size n, ForwardIter2 result);
namespace ranges {
template<class I, class O>
using copy_n_result = in_out_result<I, O>;
template<input_iterator I, weakly_incrementable O>
requires indirectly_copyable<I, O>
constexpr copy_n_result<I, O> copy_n(I first, iter_difference_t<I> n, O result);
}
template<class InputIter, class OutputIter, class Pred>
constexpr OutputIter copy_if(InputIter first, InputIter last,
OutputIter result, Pred pred);
template<class ExecutionPolicy,
class ForwardIter1, class ForwardIter2, class Pred>
ForwardIter2 copy_if(ExecutionPolicy&& exec,
ForwardIter1 first, ForwardIter1 last,
ForwardIter2 result, Pred pred);
namespace ranges {
template<class I, class O>
using copy_if_result = in_out_result<I, O>;
template<input_iterator I, sentinel_for<I> S, weakly_incrementable O,
class Proj = identity, indirect_unary_predicate<projected<I, Proj>> Pred>
requires indirectly_copyable<I, O>
constexpr copy_if_result<I, O>
copy_if(I first, S last, O result, Pred pred, Proj proj = {});
template<input_range R, weakly_incrementable O, class Proj = identity,
indirect_unary_predicate<projected<iterator_t<R>, Proj>> Pred>
requires indirectly_copyable<iterator_t<R>, O>
constexpr copy_if_result<borrowed_iterator_t<R>, O>
copy_if(R&& r, O result, Pred pred, Proj proj = {});
}
template<class BidirectionalIter1, class BidirectionalIter2>
constexpr BidirectionalIter2
copy_backward(BidirectionalIter1 first, BidirectionalIter1 last,
BidirectionalIter2 result);
namespace ranges {
template<class I1, class I2>
using copy_backward_result = in_out_result<I1, I2>;
template<bidirectional_iterator I1, sentinel_for<I1> S1, bidirectional_iterator I2>
requires indirectly_copyable<I1, I2>
constexpr copy_backward_result<I1, I2>
copy_backward(I1 first, S1 last, I2 result);
template<bidirectional_range R, bidirectional_iterator I>
requires indirectly_copyable<iterator_t<R>, I>
constexpr copy_backward_result<borrowed_iterator_t<R>, I>
copy_backward(R&& r, I result);
}
// move
template<class InputIter, class OutputIter>
constexpr OutputIter move(InputIter first, InputIter last, OutputIter result);
template<class ExecutionPolicy, class ForwardIter1,
class ForwardIter2>
ForwardIter2 move(ExecutionPolicy&& exec,
ForwardIter1 first, ForwardIter1 last, ForwardIter2 result);
namespace ranges {
template<class I, class O>
using move_result = in_out_result<I, O>;
template<input_iterator I, sentinel_for<I> S, weakly_incrementable O>
requires indirectly_movable<I, O>
constexpr move_result<I, O> move(I first, S last, O result);
template<input_range R, weakly_incrementable O>
requires indirectly_movable<iterator_t<R>, O>
constexpr move_result<borrowed_iterator_t<R>, O> move(R&& r, O result);
}
template<class BidirectionalIter1, class BidirectionalIter2>
constexpr BidirectionalIter2
move_backward(BidirectionalIter1 first, BidirectionalIter1 last,
BidirectionalIter2 result);
namespace ranges {
template<class I1, class I2>
using move_backward_result = in_out_result<I1, I2>;
template<bidirectional_iterator I1, sentinel_for<I1> S1, bidirectional_iterator I2>
requires indirectly_movable<I1, I2>
constexpr move_backward_result<I1, I2>
move_backward(I1 first, S1 last, I2 result);
template<bidirectional_range R, bidirectional_iterator I>
requires indirectly_movable<iterator_t<R>, I>
constexpr move_backward_result<borrowed_iterator_t<R>, I>
move_backward(R&& r, I result);
}
// swap
template<class ForwardIter1, class ForwardIter2>
constexpr ForwardIter2 swap_ranges(ForwardIter1 first1, ForwardIter1 last1,
ForwardIter2 first2);
template<class ExecutionPolicy, class ForwardIter1, class ForwardIter2>
ForwardIter2 swap_ranges(ExecutionPolicy&& exec,
ForwardIter1 first1, ForwardIter1 last1,
ForwardIter2 first2);
namespace ranges {
template<class I1, class I2>
using swap_ranges_result = in_in_result<I1, I2>;
template<input_iterator I1, sentinel_for<I1> S1,
input_iterator I2, sentinel_for<I2> S2>
requires indirectly_swappable<I1, I2>
constexpr swap_ranges_result<I1, I2>
swap_ranges(I1 first1, S1 last1, I2 first2, S2 last2);
template<input_range R1, input_range R2>
requires indirectly_swappable<iterator_t<R1>, iterator_t<R2>>
constexpr swap_ranges_result<borrowed_iterator_t<R1>, borrowed_iterator_t<R2>>
swap_ranges(R1&& r1, R2&& r2);
}
template<class ForwardIter1, class ForwardIter2>
constexpr void iter_swap(ForwardIter1 a, ForwardIter2 b);
// transform
template<class InputIter, class OutputIter, class UnaryOperation>
constexpr OutputIter
transform(InputIter first1, InputIter last1,
OutputIter result, UnaryOperation op);
template<class InputIter1, class InputIter2, class OutputIter,
class BinaryOperation>
constexpr OutputIter
transform(InputIter1 first1, InputIter1 last1,
InputIter2 first2, OutputIter result,
BinaryOperation binary_op);
template<class ExecutionPolicy, class ForwardIter1, class ForwardIter2,
class UnaryOperation>
ForwardIter2
transform(ExecutionPolicy&& exec,
ForwardIter1 first1, ForwardIter1 last1,
ForwardIter2 result, UnaryOperation op);
template<class ExecutionPolicy, class ForwardIter1, class ForwardIter2,
class ForwardIter, class BinaryOperation>
ForwardIter
transform(ExecutionPolicy&& exec,
ForwardIter1 first1, ForwardIter1 last1,
ForwardIter2 first2, ForwardIter result,
BinaryOperation binary_op);
namespace ranges {
template<class I, class O>
using unary_transform_result = in_out_result<I, O>;
template<input_iterator I, sentinel_for<I> S, weakly_incrementable O,
copy_constructible F, class Proj = identity>
requires indirectly_writable<O, indirect_result_t<F&, projected<I, Proj>>>
constexpr unary_transform_result<I, O>
transform(I first1, S last1, O result, F op, Proj proj = {});
template<input_range R, weakly_incrementable O,
copy_constructible F, class Proj = identity>
requires
indirectly_writable<O, indirect_result_t<F&, projected<iterator_t<R>, Proj>>>
constexpr unary_transform_result<borrowed_iterator_t<R>, O>
transform(R&& r, O result, F op, Proj proj = {});
template<class I1, class I2, class O>
using binary_transform_result = in_in_out_result<I1, I2, O>;
template<input_iterator I1, sentinel_for<I1> S1, input_iterator I2,
sentinel_for<I2> S2, weakly_incrementable O, copy_constructible F,
class Proj1 = identity, class Proj2 = identity>
requires indirectly_writable<O, indirect_result_t<F&, projected<I1, Proj1>,
projected<I2, Proj2>>>
constexpr binary_transform_result<I1, I2, O>
transform(I1 first1, S1 last1, I2 first2, S2 last2, O result,
F binary_op, Proj1 proj1 = {}, Proj2 proj2 = {});
template<input_range R1, input_range R2, weakly_incrementable O,
copy_constructible F, class Proj1 = identity, class Proj2 = identity>
requires indirectly_writable
<O, indirect_result_t<F&, projected<iterator_t<R1>, Proj1>,
projected<iterator_t<R2>, Proj2>>>
constexpr binary_transform_result<borrowed_iterator_t<R1>,
borrowed_iterator_t<R2>, O>
transform(R1&& r1, R2&& r2, O result,
F binary_op, Proj1 proj1 = {}, Proj2 proj2 = {});
}
// replace
template<class ForwardIter, class T = typename iterator_traits<ForwardIter>::value_type>
constexpr void replace(ForwardIter first, ForwardIter last,
const T& old_value, const T& new_value);
template<class ExecutionPolicy, class ForwardIter,
class T = typename iterator_traits<ForwardIter>::value_type>
void replace(ExecutionPolicy&& exec,
ForwardIter first, ForwardIter last,
const T& old_value, const T& new_value);
template<class ForwardIter, class Pred,
class T = typename iterator_traits<ForwardIter>::value_type>
constexpr void replace_if(ForwardIter first, ForwardIter last,
Pred pred, const T& new_value);
template<class ExecutionPolicy, class ForwardIter, class Pred,
class T = typename iterator_traits<ForwardIter>::value_type>
void replace_if(ExecutionPolicy&& exec,
ForwardIter first, ForwardIter last,
Pred pred, const T& new_value);
namespace ranges {
template<input_iterator I, sentinel_for<I> S,
class Proj = identity, class T1 = projected_value_t<I, Proj>, class T2 = T1>
requires indirectly_writable<I, const T2&> &&
indirect_binary_predicate<ranges::equal_to, projected<I, Proj>, const T1*>
constexpr I replace(I first, S last, const T1& old_value,
const T2& new_value, Proj proj = {});
template<input_range R, class Proj = identity,
class T1 = projected_value_t<iterator_t<R>, Proj>, class T2 = T1>
requires indirectly_writable<iterator_t<R>, const T2&> &&
indirect_binary_predicate<ranges::equal_to,
projected<iterator_t<R>, Proj>, const T1*>
constexpr borrowed_iterator_t<R> replace(R&& r, const T1& old_value,
const T2& new_value, Proj proj = {});
template<input_iterator I, sentinel_for<I> S, class Proj = identity,
class T = projected_value_t<I, Proj>,
indirect_unary_predicate<projected<I, Proj>> Pred>
requires indirectly_writable<I, const T&>
constexpr I replace_if(I first, S last, Pred pred,
const T& new_value, Proj proj = {});
template<input_range R, class Proj = identity,
class T = projected_value_t<iterator_t<R>, Proj>,
indirect_unary_predicate<projected<iterator_t<R>, Proj>> Pred>
requires indirectly_writable<iterator_t<R>, const T&>
constexpr borrowed_iterator_t<R> replace_if(R&& r, Pred pred,
const T& new_value, Proj proj = {});
}
template<class InputIter, class OutputIter, class T>
constexpr OutputIter replace_copy(InputIter first, InputIter last, OutputIter result,
const T& old_value, const T& new_value);
template<class ExecutionPolicy, class ForwardIter1, class ForwardIter2, class T>
ForwardIter2 replace_copy(ExecutionPolicy&& exec,
ForwardIter1 first, ForwardIter1 last, ForwardIter2 result,
const T& old_value, const T& new_value);
template<class InputIter, class OutputIter, class Pred,
class T = typename iterator_traits<OutputIter>::value_type>
constexpr OutputIter replace_copy_if(InputIter first, InputIter last,
OutputIter result,
Pred pred, const T& new_value);
template<class ExecutionPolicy, class ForwardIter1, class ForwardIter2,
class Pred, class T = typename iterator_traits<ForwardIter2>::value_type>
ForwardIter2 replace_copy_if(ExecutionPolicy&& exec,
ForwardIter1 first, ForwardIter1 last,
ForwardIter2 result,
Pred pred, const T& new_value);
namespace ranges {
template<class I, class O>
using replace_copy_result = in_out_result<I, O>;
template<input_iterator I, sentinel_for<I> S, class O, class Proj = identity,
class T1 = projected_value_t<I, Proj>, class T2 = iter_value_t<O>>
requires indirectly_copyable<I, O> &&
indirect_binary_predicate<ranges::equal_to,
projected<I, Proj>, const T1*> &&
output_iterator<O, const T2&>
constexpr replace_copy_result<I, O>
replace_copy(I first, S last, O result, const T1& old_value,
const T2& new_value, Proj proj = {});
template<input_range R, class O, class Proj = identity,
class T1 = projected_value_t<iterator_t<R>, Proj>,
class T2 = iter_value_t<O>>
requires indirectly_copyable<iterator_t<R>, O> &&
indirect_binary_predicate<ranges::equal_to,
projected<iterator_t<R>, Proj>, const T1*> &&
output_iterator<O, const T2&>
constexpr replace_copy_result<borrowed_iterator_t<R>, O>
replace_copy(R&& r, O result, const T1& old_value,
const T2& new_value, Proj proj = {});
template<class I, class O>
using replace_copy_if_result = in_out_result<I, O>;
template<input_iterator I, sentinel_for<I> S, class O, class T = iter_value_t<O>,
class Proj = identity, indirect_unary_predicate<projected<I, Proj>> Pred>
requires indirectly_copyable<I, O> && output_iterator<O, const T&>
constexpr replace_copy_if_result<I, O>
replace_copy_if(I first, S last, O result, Pred pred,
const T& new_value, Proj proj = {});
template<input_range R, class O, class T = iter_value_t<O>, class Proj = identity,
indirect_unary_predicate<projected<iterator_t<R>, Proj>> Pred>
requires indirectly_copyable<iterator_t<R>, O> && output_iterator<O, const T&>
constexpr replace_copy_if_result<borrowed_iterator_t<R>, O>
replace_copy_if(R&& r, O result, Pred pred,
const T& new_value, Proj proj = {});
}
// fill
template<class ForwardIter, class T = typename iterator_traits<ForwardIter>::value_type>
constexpr void fill(ForwardIter first, ForwardIter last, const T& value);
template<class ExecutionPolicy, class ForwardIter,
class T = typename iterator_traits<ForwardIter>::value_type>
void fill(ExecutionPolicy&& exec,
ForwardIter first, ForwardIter last, const T& value);
template<class OutputIter, class Size,
class T = typename iterator_traits<OutputIter>::value_type>
constexpr OutputIter fill_n(OutputIter first, Size n, const T& value);
template<class ExecutionPolicy, class ForwardIter,
class Size, class T = typename iterator_traits<OutputIter>::value_type>
ForwardIter fill_n(ExecutionPolicy&& exec,
ForwardIter first, Size n, const T& value);
namespace ranges {
template<class O, sentinel_for<O> S, class T = iter_value_t<O>>
requires output_iterator<O, const T&>
constexpr O fill(O first, S last, const T& value);
template<class R, class T = range_value_t<R>>
requires output_range<R, const T&>
constexpr borrowed_iterator_t<R> fill(R&& r, const T& value);
template<class O, class T = iter_value_t<O>>
requires output_iterator<O, const T&>
constexpr O fill_n(O first, iter_difference_t<O> n, const T& value);
}
// generate
template<class ForwardIter, class Generator>
constexpr void generate(ForwardIter first, ForwardIter last, Generator gen);
template<class ExecutionPolicy, class ForwardIter, class Generator>
void generate(ExecutionPolicy&& exec,
ForwardIter first, ForwardIter last, Generator gen);
template<class OutputIter, class Size, class Generator>
constexpr OutputIter generate_n(OutputIter first, Size n, Generator gen);
template<class ExecutionPolicy, class ForwardIter, class Size, class Generator>
ForwardIter generate_n(ExecutionPolicy&& exec,
ForwardIter first, Size n, Generator gen);
namespace ranges {
template<input_or_output_iterator O, sentinel_for<O> S, copy_constructible F>
requires invocable<F&> && indirectly_writable<O, invoke_result_t<F&>>
constexpr O generate(O first, S last, F gen);
template<class R, copy_constructible F>
requires invocable<F&> && output_range<R, invoke_result_t<F&>>
constexpr borrowed_iterator_t<R> generate(R&& r, F gen);
template<input_or_output_iterator O, copy_constructible F>
requires invocable<F&> && indirectly_writable<O, invoke_result_t<F&>>
constexpr O generate_n(O first, iter_difference_t<O> n, F gen);
}
// remove
template<class ForwardIter, class T = typename iterator_traits<ForwardIter>::value_type>
constexpr ForwardIter remove(ForwardIter first, ForwardIter last, const T& value);
template<class ExecutionPolicy, class ForwardIter,
class T = typename iterator_traits<ForwardIter>::value_type>
ForwardIter remove(ExecutionPolicy&& exec,
ForwardIter first, ForwardIter last, const T& value);
template<class ForwardIter, class Pred>
constexpr ForwardIter remove_if(ForwardIter first, ForwardIter last, Pred pred);
template<class ExecutionPolicy, class ForwardIter, class Pred>
ForwardIter remove_if(ExecutionPolicy&& exec,
ForwardIter first, ForwardIter last, Pred pred);
namespace ranges {
template<permutable I, sentinel_for<I> S, class Proj = identity,
class T = projected_value_t<I, Proj>>
requires indirect_binary_predicate<ranges::equal_to, projected<I, Proj>, const T*>
constexpr subrange<I> remove(I first, S last, const T& value, Proj proj = {});
template<forward_range R, class Proj = identity,
class T = projected_value_t<iterator_t<R>, Proj>>
requires permutable<iterator_t<R>> &&
indirect_binary_predicate<ranges::equal_to,
projected<iterator_t<R>, Proj>, const T*>
constexpr borrowed_subrange_t<R> remove(R&& r, const T& value, Proj proj = {});
template<permutable I, sentinel_for<I> S, class Proj = identity,
indirect_unary_predicate<projected<I, Proj>> Pred>
constexpr subrange<I> remove_if(I first, S last, Pred pred, Proj proj = {});
template<forward_range R, class Proj = identity,
indirect_unary_predicate<projected<iterator_t<R>, Proj>> Pred>
requires permutable<iterator_t<R>>
constexpr borrowed_subrange_t<R> remove_if(R&& r, Pred pred, Proj proj = {});
}
template<class InputIter, class OutputIter,
class T = typename iterator_traits<InputIter>::value_type>
constexpr OutputIter remove_copy(InputIter first, InputIter last,
OutputIter result, const T& value);
template<class ExecutionPolicy, class ForwardIter1, class ForwardIter2,
class T = typename iterator_traits<ForwardIter1>::value_type>
ForwardIter2 remove_copy(ExecutionPolicy&& exec,
ForwardIter1 first, ForwardIter1 last,
ForwardIter2 result, const T& value);
template<class InputIter, class OutputIter, class Pred>
constexpr OutputIter remove_copy_if(InputIter first, InputIter last,
OutputIter result, Pred pred);
template<class ExecutionPolicy, class ForwardIter1, class ForwardIter2, class Pred>
ForwardIter2 remove_copy_if(ExecutionPolicy&& exec,
ForwardIter1 first, ForwardIter1 last,
ForwardIter2 result, Pred pred);
namespace ranges {
template<class I, class O>
using remove_copy_result = in_out_result<I, O>;
template<input_iterator I, sentinel_for<I> S, weakly_incrementable O,
class Proj = identity, class T = projected_value_t<I, Proj>>
requires indirectly_copyable<I, O> &&
indirect_binary_predicate<ranges::equal_to, projected<I, Proj>, const T*>
constexpr remove_copy_result<I, O>
remove_copy(I first, S last, O result, const T& value, Proj proj = {});
template<input_range R, weakly_incrementable O, class Proj = identity,
class T = projected_value_t<iterator_t<R>, Proj>>
requires indirectly_copyable<iterator_t<R>, O> &&
indirect_binary_predicate<ranges::equal_to,
projected<iterator_t<R>, Proj>, const T*>
constexpr remove_copy_result<borrowed_iterator_t<R>, O>
remove_copy(R&& r, O result, const T& value, Proj proj = {});
template<class I, class O>
using remove_copy_if_result = in_out_result<I, O>;
template<input_iterator I, sentinel_for<I> S, weakly_incrementable O,
class Proj = identity, indirect_unary_predicate<projected<I, Proj>> Pred>
requires indirectly_copyable<I, O>
constexpr remove_copy_if_result<I, O>
remove_copy_if(I first, S last, O result, Pred pred, Proj proj = {});
template<input_range R, weakly_incrementable O, class Proj = identity,
indirect_unary_predicate<projected<iterator_t<R>, Proj>> Pred>
requires indirectly_copyable<iterator_t<R>, O>
constexpr remove_copy_if_result<borrowed_iterator_t<R>, O>
remove_copy_if(R&& r, O result, Pred pred, Proj proj = {});
}
// unique
template<class ForwardIter>
constexpr ForwardIter unique(ForwardIter first, ForwardIter last);
template<class ForwardIter, class BinaryPred>
constexpr ForwardIter unique(ForwardIter first, ForwardIter last, BinaryPred pred);
template<class ExecutionPolicy, class ForwardIter>
ForwardIter unique(ExecutionPolicy&& exec,
ForwardIter first, ForwardIter last);
template<class ExecutionPolicy, class ForwardIter, class BinaryPred>
ForwardIter unique(ExecutionPolicy&& exec,
ForwardIter first, ForwardIter last, BinaryPred pred);
namespace ranges {
template<permutable I, sentinel_for<I> S, class Proj = identity,
indirect_equivalence_relation<projected<I, Proj>> C = ranges::equal_to>
constexpr subrange<I> unique(I first, S last, C comp = {}, Proj proj = {});
template<forward_range R, class Proj = identity,
indirect_equivalence_relation
<projected<iterator_t<R>, Proj>> C = ranges::equal_to>
requires permutable<iterator_t<R>>
constexpr borrowed_subrange_t<R> unique(R&& r, C comp = {}, Proj proj = {});
}
template<class InputIter, class OutputIter>
constexpr OutputIter unique_copy(InputIter first, InputIter last,
OutputIter result);
template<class InputIter, class OutputIter, class BinaryPred>
constexpr OutputIter unique_copy(InputIter first, InputIter last,
OutputIter result, BinaryPred pred);
template<class ExecutionPolicy, class ForwardIter1, class ForwardIter2>
ForwardIter2 unique_copy(ExecutionPolicy&& exec,
ForwardIter1 first, ForwardIter1 last,
ForwardIter2 result);
template<class ExecutionPolicy, class ForwardIter1, class ForwardIter2,
class BinaryPred>
ForwardIter2 unique_copy(ExecutionPolicy&& exec,
ForwardIter1 first, ForwardIter1 last,
ForwardIter2 result, BinaryPred pred);
namespace ranges {
template<class I, class O>
using unique_copy_result = in_out_result<I, O>;
template<input_iterator I, sentinel_for<I> S,
weakly_incrementable O, class Proj = identity,
indirect_equivalence_relation<projected<I, Proj>> C = ranges::equal_to>
requires indirectly_copyable<I, O> &&
(forward_iterator<I> ||
(input_iterator<O> && same_as<iter_value_t<I>, iter_value_t<O>>) ||
indirectly_copyable_storable<I, O>)
constexpr unique_copy_result<I, O>
unique_copy(I first, S last, O result, C comp = {}, Proj proj = {});
template<input_range R, weakly_incrementable O, class Proj = identity,
indirect_equivalence_relation
<projected<iterator_t<R>, Proj>> C = ranges::equal_to>
requires indirectly_copyable<iterator_t<R>, O> &&
(forward_iterator<iterator_t<R>> ||
(input_iterator<O> && same_as<range_value_t<R>, iter_value_t<O>>) ||
indirectly_copyable_storable<iterator_t<R>, O>)
constexpr unique_copy_result<borrowed_iterator_t<R>, O>
unique_copy(R&& r, O result, C comp = {}, Proj proj = {});
}
// reverse
template<class BidirectionalIter>
constexpr void reverse(BidirectionalIter first, BidirectionalIter last);
template<class ExecutionPolicy, class BidirectionalIter>
void reverse(ExecutionPolicy&& exec,
BidirectionalIter first, BidirectionalIter last);
namespace ranges {
template<bidirectional_iterator I, sentinel_for<I> S>
requires permutable<I>
constexpr I reverse(I first, S last);
template<bidirectional_range R>
requires permutable<iterator_t<R>>
constexpr borrowed_iterator_t<R> reverse(R&& r);
}
template<class BidirectionalIter, class OutputIter>
constexpr OutputIter reverse_copy(BidirectionalIter first, BidirectionalIter last,
OutputIter result);
template<class ExecutionPolicy, class BidirectionalIter, class ForwardIter>
ForwardIter reverse_copy(ExecutionPolicy&& exec,
BidirectionalIter first, BidirectionalIter last,
ForwardIter result);
namespace ranges {
template<class I, class O>
using reverse_copy_result = in_out_result<I, O>;
template<bidirectional_iterator I, sentinel_for<I> S, weakly_incrementable O>
requires indirectly_copyable<I, O>
constexpr reverse_copy_result<I, O>
reverse_copy(I first, S last, O result);
template<bidirectional_range R, weakly_incrementable O>
requires indirectly_copyable<iterator_t<R>, O>
constexpr reverse_copy_result<borrowed_iterator_t<R>, O>
reverse_copy(R&& r, O result);
}
// rotate
template<class ForwardIter>
constexpr ForwardIter rotate(ForwardIter first, ForwardIter middle, ForwardIter last);
template<class ExecutionPolicy, class ForwardIter>
ForwardIter rotate(ExecutionPolicy&& exec,
ForwardIter first, ForwardIter middle, ForwardIter last);
namespace ranges {
template<permutable I, sentinel_for<I> S>
constexpr subrange<I> rotate(I first, I middle, S last);
template<forward_range R>
requires permutable<iterator_t<R>>
constexpr borrowed_subrange_t<R> rotate(R&& r, iterator_t<R> middle);
}
template<class ForwardIter, class OutputIter>
constexpr OutputIter rotate_copy(ForwardIter first, ForwardIter middle,
ForwardIter last, OutputIter result);
template<class ExecutionPolicy, class ForwardIter1, class ForwardIter2>
ForwardIter2 rotate_copy(ExecutionPolicy&& exec,
ForwardIter1 first, ForwardIter1 middle,
ForwardIter1 last, ForwardIter2 result);
namespace ranges {
template<class I, class O>
using rotate_copy_result = in_out_result<I, O>;
template<forward_iterator I, sentinel_for<I> S, weakly_incrementable O>
requires indirectly_copyable<I, O>
constexpr rotate_copy_result<I, O>
rotate_copy(I first, I middle, S last, O result);
template<forward_range R, weakly_incrementable O>
requires indirectly_copyable<iterator_t<R>, O>
constexpr rotate_copy_result<borrowed_iterator_t<R>, O>
rotate_copy(R&& r, iterator_t<R> middle, O result);
}
// sample
template<class PopulationIter, class SampleIter,
class Distance, class UniformRandomBitGenerator>
SampleIter sample(PopulationIter first, PopulationIter last,
SampleIter out, Distance n, UniformRandomBitGenerator&& g);
namespace ranges {
template<input_iterator I, sentinel_for<I> S,
weakly_incrementable O, class Gen>
requires (forward_iterator<I> || random_access_iterator<O>) &&
indirectly_copyable<I, O> &&
uniform_random_bit_generator<remove_reference_t<Gen>>
O sample(I first, S last, O out, iter_difference_t<I> n, Gen&& g);
template<input_range R, weakly_incrementable O, class Gen>
requires (forward_range<R> || random_access_iterator<O>) &&
indirectly_copyable<iterator_t<R>, O> &&
uniform_random_bit_generator<remove_reference_t<Gen>>
O sample(R&& r, O out, range_difference_t<R> n, Gen&& g);
}
// shuffle
template<class RandomAccessIter, class UniformRandomBitGenerator>
void shuffle(RandomAccessIter first, RandomAccessIter last,
UniformRandomBitGenerator&& g);
namespace ranges {
template<random_access_iterator I, sentinel_for<I> S, class Gen>
requires permutable<I> &&
uniform_random_bit_generator<remove_reference_t<Gen>>
I shuffle(I first, S last, Gen&& g);
template<random_access_range R, class Gen>
requires permutable<iterator_t<R>> &&
uniform_random_bit_generator<remove_reference_t<Gen>>
borrowed_iterator_t<R> shuffle(R&& r, Gen&& g);
}
// shift
template<class ForwardIter>
constexpr ForwardIter
shift_left(ForwardIter first, ForwardIter last,
typename iterator_traits<ForwardIter>::difference_type n);
template<class ExecutionPolicy, class ForwardIter>
ForwardIter
shift_left(ExecutionPolicy&& exec,
ForwardIter first, ForwardIter last,
typename iterator_traits<ForwardIter>::difference_type n);
namespace ranges {
template<permutable I, sentinel_for<I> S>
constexpr subrange<I> shift_left(I first, S last, iter_difference_t<I> n);
template<forward_range R>
requires permutable<iterator_t<R>>
constexpr borrowed_subrange_t<R> shift_left(R&& r, range_difference_t<R> n);
}
template<class ForwardIter>
constexpr ForwardIter
shift_right(ForwardIter first, ForwardIter last,
typename iterator_traits<ForwardIter>::difference_type n);
template<class ExecutionPolicy, class ForwardIter>
ForwardIter
shift_right(ExecutionPolicy&& exec,
ForwardIter first, ForwardIter last,
typename iterator_traits<ForwardIter>::difference_type n);
namespace ranges {
template<permutable I, sentinel_for<I> S>
constexpr subrange<I> shift_right(I first, S last, iter_difference_t<I> n);
template<forward_range R>
requires permutable<iterator_t<R>>
constexpr borrowed_subrange_t<R> shift_right(R&& r, range_difference_t<R> n);
}
// sorting and related operations
// sorting
template<class RandomAccessIter>
constexpr void sort(RandomAccessIter first, RandomAccessIter last);
template<class RandomAccessIter, class Compare>
constexpr void sort(RandomAccessIter first, RandomAccessIter last, Compare comp);
template<class ExecutionPolicy, class RandomAccessIter>
void sort(ExecutionPolicy&& exec,
RandomAccessIter first, RandomAccessIter last);
template<class ExecutionPolicy, class RandomAccessIter, class Compare>
void sort(ExecutionPolicy&& exec,
RandomAccessIter first, RandomAccessIter last, Compare comp);
namespace ranges {
template<random_access_iterator I, sentinel_for<I> S,
class Comp = ranges::less, class Proj = identity>
requires sortable<I, Comp, Proj>
constexpr I sort(I first, S last, Comp comp = {}, Proj proj = {});
template<random_access_range R, class Comp = ranges::less, class Proj = identity>
requires sortable<iterator_t<R>, Comp, Proj>
constexpr borrowed_iterator_t<R> sort(R&& r, Comp comp = {}, Proj proj = {});
}
template<class RandomAccessIter>
void stable_sort(RandomAccessIter first, RandomAccessIter last);
template<class RandomAccessIter, class Compare>
void stable_sort(RandomAccessIter first, RandomAccessIter last, Compare comp);
template<class ExecutionPolicy, class RandomAccessIter>
void stable_sort(ExecutionPolicy&& exec,
RandomAccessIter first, RandomAccessIter last);
template<class ExecutionPolicy, class RandomAccessIter, class Compare>
void stable_sort(ExecutionPolicy&& exec,
RandomAccessIter first, RandomAccessIter last, Compare comp);
namespace ranges {
template<random_access_iterator I, sentinel_for<I> S,
class Comp = ranges::less, class Proj = identity>
requires sortable<I, Comp, Proj>
I stable_sort(I first, S last, Comp comp = {}, Proj proj = {});
template<random_access_range R, class Comp = ranges::less, class Proj = identity>
requires sortable<iterator_t<R>, Comp, Proj>
borrowed_iterator_t<R> stable_sort(R&& r, Comp comp = {}, Proj proj = {});
}
template<class RandomAccessIter>
constexpr void partial_sort(RandomAccessIter first, RandomAccessIter middle,
RandomAccessIter last);
template<class RandomAccessIter, class Compare>
constexpr void partial_sort(RandomAccessIter first, RandomAccessIter middle,
RandomAccessIter last, Compare comp);
template<class ExecutionPolicy, class RandomAccessIter>
void partial_sort(ExecutionPolicy&& exec,
RandomAccessIter first, RandomAccessIter middle,
RandomAccessIter last);
template<class ExecutionPolicy, class RandomAccessIter, class Compare>
void partial_sort(ExecutionPolicy&& exec,
RandomAccessIter first, RandomAccessIter middle,
RandomAccessIter last, Compare comp);
namespace ranges {
template<random_access_iterator I, sentinel_for<I> S,
class Comp = ranges::less, class Proj = identity>
requires sortable<I, Comp, Proj>
constexpr I
partial_sort(I first, I middle, S last, Comp comp = {}, Proj proj = {});
template<random_access_range R, class Comp = ranges::less, class Proj = identity>
requires sortable<iterator_t<R>, Comp, Proj>
constexpr borrowed_iterator_t<R>
partial_sort(R&& r, iterator_t<R> middle, Comp comp = {}, Proj proj = {});
}
template<class InputIter, class RandomAccessIter>
constexpr RandomAccessIter
partial_sort_copy(InputIter first, InputIter last,
RandomAccessIter result_first,
RandomAccessIter result_last);
template<class InputIter, class RandomAccessIter, class Compare>
constexpr RandomAccessIter
partial_sort_copy(InputIter first, InputIter last,
RandomAccessIter result_first,
RandomAccessIter result_last, Compare comp);
template<class ExecutionPolicy, class ForwardIter, class RandomAccessIter>
RandomAccessIter
partial_sort_copy(ExecutionPolicy&& exec,
ForwardIter first, ForwardIter last,
RandomAccessIter result_first,
RandomAccessIter result_last);
template<class ExecutionPolicy, class ForwardIter, class RandomAccessIter,
class Compare>
RandomAccessIter
partial_sort_copy(ExecutionPolicy&& exec,
ForwardIter first, ForwardIter last,
RandomAccessIter result_first,
RandomAccessIter result_last, Compare comp);
namespace ranges {
template<class I, class O>
using partial_sort_copy_result = in_out_result<I, O>;
template<input_iterator I1, sentinel_for<I1> S1,
random_access_iterator I2, sentinel_for<I2> S2,
class Comp = ranges::less, class Proj1 = identity, class Proj2 = identity>
requires indirectly_copyable<I1, I2> && sortable<I2, Comp, Proj2> &&
indirect_strict_weak_order<Comp, projected<I1, Proj1>,
projected<I2, Proj2>>
constexpr partial_sort_copy_result<I1, I2>
partial_sort_copy(I1 first, S1 last, I2 result_first, S2 result_last,
Comp comp = {}, Proj1 proj1 = {}, Proj2 proj2 = {});
template<input_range R1, random_access_range R2, class Comp = ranges::less,
class Proj1 = identity, class Proj2 = identity>
requires indirectly_copyable<iterator_t<R1>, iterator_t<R2>> &&
sortable<iterator_t<R2>, Comp, Proj2> &&
indirect_strict_weak_order<Comp, projected<iterator_t<R1>, Proj1>,
projected<iterator_t<R2>, Proj2>>
constexpr partial_sort_copy_result<borrowed_iterator_t<R1>, borrowed_iterator_t<R2>>
partial_sort_copy(R1&& r, R2&& result_r, Comp comp = {},
Proj1 proj1 = {}, Proj2 proj2 = {});
}
template<class ForwardIter>
constexpr bool is_sorted(ForwardIter first, ForwardIter last);
template<class ForwardIter, class Compare>
constexpr bool is_sorted(ForwardIter first, ForwardIter last, Compare comp);
template<class ExecutionPolicy, class ForwardIter>
bool is_sorted(ExecutionPolicy&& exec,
ForwardIter first, ForwardIter last);
template<class ExecutionPolicy, class ForwardIter, class Compare>
bool is_sorted(ExecutionPolicy&& exec,
ForwardIter first, ForwardIter last, Compare comp);
namespace ranges {
template<forward_iterator I, sentinel_for<I> S, class Proj = identity,
indirect_strict_weak_order<projected<I, Proj>> Comp = ranges::less>
constexpr bool is_sorted(I first, S last, Comp comp = {}, Proj proj = {});
template<forward_range R, class Proj = identity,
indirect_strict_weak_order
<projected<iterator_t<R>, Proj>> Comp = ranges::less>
constexpr bool is_sorted(R&& r, Comp comp = {}, Proj proj = {});
}
template<class ForwardIter>
constexpr ForwardIter is_sorted_until(ForwardIter first, ForwardIter last);
template<class ForwardIter, class Compare>
constexpr ForwardIter is_sorted_until(ForwardIter first, ForwardIter last,
Compare comp);
template<class ExecutionPolicy, class ForwardIter>
ForwardIter is_sorted_until(ExecutionPolicy&& exec,
ForwardIter first, ForwardIter last);
template<class ExecutionPolicy, class ForwardIter, class Compare>
ForwardIter is_sorted_until(ExecutionPolicy&& exec,
ForwardIter first, ForwardIter last,
Compare comp);
namespace ranges {
template<forward_iterator I, sentinel_for<I> S, class Proj = identity,
indirect_strict_weak_order<projected<I, Proj>> Comp = ranges::less>
constexpr I is_sorted_until(I first, S last, Comp comp = {}, Proj proj = {});
template<forward_range R, class Proj = identity,
indirect_strict_weak_order
<projected<iterator_t<R>, Proj>> Comp = ranges::less>
constexpr borrowed_iterator_t<R>
is_sorted_until(R&& r, Comp comp = {}, Proj proj = {});
}
// Nth element
template<class RandomAccessIter>
constexpr void nth_element(RandomAccessIter first, RandomAccessIter nth,
RandomAccessIter last);
template<class RandomAccessIter, class Compare>
constexpr void nth_element(RandomAccessIter first, RandomAccessIter nth,
RandomAccessIter last, Compare comp);
template<class ExecutionPolicy, class RandomAccessIter>
void nth_element(ExecutionPolicy&& exec,
RandomAccessIter first, RandomAccessIter nth,
RandomAccessIter last);
template<class ExecutionPolicy, class RandomAccessIter, class Compare>
void nth_element(ExecutionPolicy&& exec,
RandomAccessIter first, RandomAccessIter nth,
RandomAccessIter last, Compare comp);
namespace ranges {
template<random_access_iterator I, sentinel_for<I> S,
class Comp = ranges::less, class Proj = identity>
requires sortable<I, Comp, Proj>
constexpr I
nth_element(I first, I nth, S last, Comp comp = {}, Proj proj = {});
template<random_access_range R, class Comp = ranges::less, class Proj = identity>
requires sortable<iterator_t<R>, Comp, Proj>
constexpr borrowed_iterator_t<R>
nth_element(R&& r, iterator_t<R> nth, Comp comp = {}, Proj proj = {});
}
// binary search
template<class ForwardIter, class T = typename iterator_traits<ForwardIter>::value_type>
constexpr ForwardIter lower_bound(ForwardIter first, ForwardIter last,
const T& value);
template<class ForwardIter, class T = typename iterator_traits<ForwardIter>::value_type,
class Compare>
constexpr ForwardIter lower_bound(ForwardIter first, ForwardIter last,
const T& value, Compare comp);
namespace ranges {
template<forward_iterator I, sentinel_for<I> S, class Proj = identity,
class T = projected_value_t<I, Proj>,
indirect_strict_weak_order<const T*, projected<I, Proj>> Comp = ranges::less>
constexpr I
lower_bound(I first, S last, const T& value, Comp comp = {}, Proj proj = {});
template<forward_range R, class Proj = identity,
class T = projected_value_t<iterator_t<R>, Proj>,
indirect_strict_weak_order
<const T*, projected<iterator_t<R>, Proj>> Comp = ranges::less>
constexpr borrowed_iterator_t<R>
lower_bound(R&& r, const T& value, Comp comp = {}, Proj proj = {});
}
template<class ForwardIter, class T = typename iterator_traits<ForwardIter>::value_type>
constexpr ForwardIter upper_bound(ForwardIter first, ForwardIter last,
const T& value);
template<class ForwardIter, class T = typename iterator_traits<ForwardIter>::value_type,
class Compare>
constexpr ForwardIter upper_bound(ForwardIter first, ForwardIter last,
const T& value, Compare comp);
namespace ranges {
template<forward_iterator I, sentinel_for<I> S, class Proj = identity,
class T = projected_value_t<I, Proj>,
indirect_strict_weak_order<const T*, projected<I, Proj>> Comp = ranges::less>
constexpr I
upper_bound(I first, S last, const T& value, Comp comp = {}, Proj proj = {});
template<forward_range R, class T, class Proj = identity,
class T = projected_value_t<iterator_t<R>, Proj>,
indirect_strict_weak_order
<const T*, projected<iterator_t<R>, Proj>> Comp = ranges::less>
constexpr borrowed_iterator_t<R>
upper_bound(R&& r, const T& value, Comp comp = {}, Proj proj = {});
}
template<class ForwardIter, class T = typename iterator_traits<ForwardIter>::value_type>
constexpr pair<ForwardIter, ForwardIter>
equal_range(ForwardIter first, ForwardIter last, const T& value);
template<class ForwardIter, class T = typename iterator_traits<ForwardIter>::value_type,
class Compare>
constexpr pair<ForwardIter, ForwardIter>
equal_range(ForwardIter first, ForwardIter last, const T& value, Compare comp);
namespace ranges {
template<forward_iterator I, sentinel_for<I> S, class Proj = identity,
class T = projected_value_t<I, Proj>,
indirect_strict_weak_order<const T*, projected<I, Proj>> Comp = ranges::less>
constexpr subrange<I>
equal_range(I first, S last, const T& value, Comp comp = {}, Proj proj = {});
template<forward_range R, class Proj = identity,
class T = projected_value_t<iterator_t<R>, Proj>,
indirect_strict_weak_order
<const T*, projected<iterator_t<R>, Proj>> Comp = ranges::less>
constexpr borrowed_subrange_t<R>
equal_range(R&& r, const T& value, Comp comp = {}, Proj proj = {});
}
template<class ForwardIter, class T = typename iterator_traits<ForwardIter>::value_type>
constexpr bool binary_search(ForwardIter first, ForwardIter last,
const T& value);
template<class ForwardIter, class T = typename iterator_traits<ForwardIter>::value_type,
class Compare>
constexpr bool binary_search(ForwardIter first, ForwardIter last,
const T& value, Compare comp);
namespace ranges {
template<forward_iterator I, sentinel_for<I> S, class Proj = identity,
class T = projected_value_t<I, Proj>,
indirect_strict_weak_order<const T*, projected<I, Proj>> Comp = ranges::less>
constexpr bool binary_search(I first, S last, const T& value,
Comp comp = {}, Proj proj = {});
template<forward_range R, class Proj = identity,
class T = projected_value_t<iterator_t<R>, Proj>,
indirect_strict_weak_order
<const T*, projected<iterator_t<R>, Proj>> Comp = ranges::less>
constexpr bool binary_search(R&& r, const T& value, Comp comp = {}, Proj proj = {});
}
// partitions
template<class InputIter, class Pred>
constexpr bool is_partitioned(InputIter first, InputIter last, Pred pred);
template<class ExecutionPolicy, class ForwardIter, class Pred>
bool is_partitioned(ExecutionPolicy&& exec,
ForwardIter first, ForwardIter last, Pred pred);
namespace ranges {
template<input_iterator I, sentinel_for<I> S, class Proj = identity,
indirect_unary_predicate<projected<I, Proj>> Pred>
constexpr bool is_partitioned(I first, S last, Pred pred, Proj proj = {});
template<input_range R, class Proj = identity,
indirect_unary_predicate<projected<iterator_t<R>, Proj>> Pred>
constexpr bool is_partitioned(R&& r, Pred pred, Proj proj = {});
}
template<class ForwardIter, class Pred>
constexpr ForwardIter partition(ForwardIter first, ForwardIter last, Pred pred);
template<class ExecutionPolicy, class ForwardIter, class Pred>
ForwardIter partition(ExecutionPolicy&& exec,
ForwardIter first, ForwardIter last, Pred pred);
namespace ranges {
template<permutable I, sentinel_for<I> S, class Proj = identity,
indirect_unary_predicate<projected<I, Proj>> Pred>
constexpr subrange<I> partition(I first, S last, Pred pred, Proj proj = {});
template<forward_range R, class Proj = identity,
indirect_unary_predicate<projected<iterator_t<R>, Proj>> Pred>
requires permutable<iterator_t<R>>
constexpr borrowed_subrange_t<R> partition(R&& r, Pred pred, Proj proj = {});
}
template<class BidirectionalIter, class Pred>
BidirectionalIter stable_partition(BidirectionalIter first,
BidirectionalIter last, Pred pred);
template<class ExecutionPolicy, class BidirectionalIter, class Pred>
BidirectionalIter stable_partition(ExecutionPolicy&& exec,
BidirectionalIter first,
BidirectionalIter last, Pred pred);
namespace ranges {
template<bidirectional_iterator I, sentinel_for<I> S, class Proj = identity,
indirect_unary_predicate<projected<I, Proj>> Pred>
requires permutable<I>
subrange<I> stable_partition(I first, S last, Pred pred, Proj proj = {});
template<bidirectional_range R, class Proj = identity,
indirect_unary_predicate<projected<iterator_t<R>, Proj>> Pred>
requires permutable<iterator_t<R>>
borrowed_subrange_t<R> stable_partition(R&& r, Pred pred, Proj proj = {});
}
template<class InputIter, class OutputIter1,
class OutputIter2, class Pred>
constexpr pair<OutputIter1, OutputIter2>
partition_copy(InputIter first, InputIter last,
OutputIter1 out_true, OutputIter2 out_false, Pred pred);
template<class ExecutionPolicy, class ForwardIter, class ForwardIter1,
class ForwardIter2, class Pred>
pair<ForwardIter1, ForwardIter2>
partition_copy(ExecutionPolicy&& exec,
ForwardIter first, ForwardIter last,
ForwardIter1 out_true, ForwardIter2 out_false, Pred pred);
namespace ranges {
template<class I, class O1, class O2>
using partition_copy_result = in_out_out_result<I, O1, O2>;
template<input_iterator I, sentinel_for<I> S,
weakly_incrementable O1, weakly_incrementable O2,
class Proj = identity, indirect_unary_predicate<projected<I, Proj>> Pred>
requires indirectly_copyable<I, O1> && indirectly_copyable<I, O2>
constexpr partition_copy_result<I, O1, O2>
partition_copy(I first, S last, O1 out_true, O2 out_false,
Pred pred, Proj proj = {});
template<input_range R, weakly_incrementable O1, weakly_incrementable O2,
class Proj = identity,
indirect_unary_predicate<projected<iterator_t<R>, Proj>> Pred>
requires indirectly_copyable<iterator_t<R>, O1> &&
indirectly_copyable<iterator_t<R>, O2>
constexpr partition_copy_result<borrowed_iterator_t<R>, O1, O2>
partition_copy(R&& r, O1 out_true, O2 out_false, Pred pred, Proj proj = {});
}
template<class ForwardIter, class Pred>
constexpr ForwardIter
partition_point(ForwardIter first, ForwardIter last, Pred pred);
namespace ranges {
template<forward_iterator I, sentinel_for<I> S, class Proj = identity,
indirect_unary_predicate<projected<I, Proj>> Pred>
constexpr I partition_point(I first, S last, Pred pred, Proj proj = {});
template<forward_range R, class Proj = identity,
indirect_unary_predicate<projected<iterator_t<R>, Proj>> Pred>
constexpr borrowed_iterator_t<R>
partition_point(R&& r, Pred pred, Proj proj = {});
}
// merge
template<class InputIter1, class InputIter2, class OutputIter>
constexpr OutputIter merge(InputIter1 first1, InputIter1 last1,
InputIter2 first2, InputIter2 last2, OutputIter result);
template<class InputIter1, class InputIter2, class OutputIter,
class Compare>
constexpr OutputIter merge(InputIter1 first1, InputIter1 last1,
InputIter2 first2, InputIter2 last2,
OutputIter result, Compare comp);
template<class ExecutionPolicy, class ForwardIter1, class ForwardIter2,
class ForwardIter>
ForwardIter merge(ExecutionPolicy&& exec,
ForwardIter1 first1, ForwardIter1 last1,
ForwardIter2 first2, ForwardIter2 last2, ForwardIter result);
template<class ExecutionPolicy, class ForwardIter1, class ForwardIter2,
class ForwardIter, class Compare>
ForwardIter merge(ExecutionPolicy&& exec,
ForwardIter1 first1, ForwardIter1 last1,
ForwardIter2 first2, ForwardIter2 last2,
ForwardIter result, Compare comp);
namespace ranges {
template<class I1, class I2, class O>
using merge_result = in_in_out_result<I1, I2, O>;
template<input_iterator I1, sentinel_for<I1> S1, input_iterator I2,
sentinel_for<I2> S2, weakly_incrementable O, class Comp = ranges::less,
class Proj1 = identity, class Proj2 = identity>
requires mergeable<I1, I2, O, Comp, Proj1, Proj2>
constexpr merge_result<I1, I2, O>
merge(I1 first1, S1 last1, I2 first2, S2 last2, O result,
Comp comp = {}, Proj1 proj1 = {}, Proj2 proj2 = {});
template<input_range R1, input_range R2, weakly_incrementable O,
class Comp = ranges::less, class Proj1 = identity, class Proj2 = identity>
requires mergeable<iterator_t<R1>, iterator_t<R2>, O, Comp, Proj1, Proj2>
constexpr merge_result<borrowed_iterator_t<R1>, borrowed_iterator_t<R2>, O>
merge(R1&& r1, R2&& r2, O result,
Comp comp = {}, Proj1 proj1 = {}, Proj2 proj2 = {});
}
template<class BidirectionalIter>
void inplace_merge(BidirectionalIter first, BidirectionalIter middle,
BidirectionalIter last);
template<class BidirectionalIter, class Compare>
void inplace_merge(BidirectionalIter first, BidirectionalIter middle,
BidirectionalIter last, Compare comp);
template<class ExecutionPolicy, class BidirectionalIter>
void inplace_merge(ExecutionPolicy&& exec,
BidirectionalIter first, BidirectionalIter middle,
BidirectionalIter last);
template<class ExecutionPolicy, class BidirectionalIter, class Compare>
void inplace_merge(ExecutionPolicy&& exec,
BidirectionalIter first, BidirectionalIter middle,
BidirectionalIter last, Compare comp);
namespace ranges {
template<bidirectional_iterator I, sentinel_for<I> S,
class Comp = ranges::less, class Proj = identity>
requires sortable<I, Comp, Proj>
I inplace_merge(I first, I middle, S last, Comp comp = {}, Proj proj = {});
template<bidirectional_range R, class Comp = ranges::less, class Proj = identity>
requires sortable<iterator_t<R>, Comp, Proj>
borrowed_iterator_t<R> inplace_merge(R&& r, iterator_t<R> middle,
Comp comp = {}, Proj proj = {});
}
// set operations
template<class InputIter1, class InputIter2>
constexpr bool includes(InputIter1 first1, InputIter1 last1,
InputIter2 first2, InputIter2 last2);
template<class InputIter1, class InputIter2, class Compare>
constexpr bool includes(InputIter1 first1, InputIter1 last1,
InputIter2 first2, InputIter2 last2, Compare comp);
template<class ExecutionPolicy, class ForwardIter1, class ForwardIter2>
bool includes(ExecutionPolicy&& exec,
ForwardIter1 first1, ForwardIter1 last1,
ForwardIter2 first2, ForwardIter2 last2);
template<class ExecutionPolicy, class ForwardIter1, class ForwardIter2, class Compare>
bool includes(ExecutionPolicy&& exec,
ForwardIter1 first1, ForwardIter1 last1,
ForwardIter2 first2, ForwardIter2 last2, Compare comp);
namespace ranges {
template<input_iterator I1, sentinel_for<I1> S1, input_iterator I2,
sentinel_for<I2> S2, class Proj1 = identity, class Proj2 = identity,
indirect_strict_weak_order
<projected<I1, Proj1>, projected<I2, Proj2>> Comp = ranges::less>
constexpr bool includes(I1 first1, S1 last1, I2 first2, S2 last2, Comp comp = {},
Proj1 proj1 = {}, Proj2 proj2 = {});
template<input_range R1, input_range R2,
class Proj1 = identity, class Proj2 = identity,
indirect_strict_weak_order
<projected<iterator_t<R1>, Proj1>,
projected<iterator_t<R2>, Proj2>> Comp = ranges::less>
constexpr bool includes(R1&& r1, R2&& r2, Comp comp = {},
Proj1 proj1 = {}, Proj2 proj2 = {});
}
template<class InputIter1, class InputIter2, class OutputIter>
constexpr OutputIter set_union(InputIter1 first1, InputIter1 last1,
InputIter2 first2, InputIter2 last2,
OutputIter result);
template<class InputIter1, class InputIter2, class OutputIter, class Compare>
constexpr OutputIter set_union(InputIter1 first1, InputIter1 last1,
InputIter2 first2, InputIter2 last2,
OutputIter result, Compare comp);
template<class ExecutionPolicy, class ForwardIter1, class ForwardIter2,
class ForwardIter>
ForwardIter set_union(ExecutionPolicy&& exec,
ForwardIter1 first1, ForwardIter1 last1,
ForwardIter2 first2, ForwardIter2 last2,
ForwardIter result);
template<class ExecutionPolicy, class ForwardIter1, class ForwardIter2,
class ForwardIter, class Compare>
ForwardIter set_union(ExecutionPolicy&& exec,
ForwardIter1 first1, ForwardIter1 last1,
ForwardIter2 first2, ForwardIter2 last2,
ForwardIter result, Compare comp);
namespace ranges {
template<class I1, class I2, class O>
using set_union_result = in_in_out_result<I1, I2, O>;
template<input_iterator I1, sentinel_for<I1> S1, input_iterator I2,
sentinel_for<I2> S2, weakly_incrementable O, class Comp = ranges::less,
class Proj1 = identity, class Proj2 = identity>
requires mergeable<I1, I2, O, Comp, Proj1, Proj2>
constexpr set_union_result<I1, I2, O>
set_union(I1 first1, S1 last1, I2 first2, S2 last2, O result, Comp comp = {},
Proj1 proj1 = {}, Proj2 proj2 = {});
template<input_range R1, input_range R2, weakly_incrementable O,
class Comp = ranges::less, class Proj1 = identity, class Proj2 = identity>
requires mergeable<iterator_t<R1>, iterator_t<R2>, O, Comp, Proj1, Proj2>
constexpr set_union_result<borrowed_iterator_t<R1>, borrowed_iterator_t<R2>, O>
set_union(R1&& r1, R2&& r2, O result, Comp comp = {},
Proj1 proj1 = {}, Proj2 proj2 = {});
}
template<class InputIter1, class InputIter2, class OutputIter>
constexpr OutputIter set_intersection(InputIter1 first1, InputIter1 last1,
InputIter2 first2, InputIter2 last2,
OutputIter result);
template<class InputIter1, class InputIter2, class OutputIter, class Compare>
constexpr OutputIter set_intersection(InputIter1 first1, InputIter1 last1,
InputIter2 first2, InputIter2 last2,
OutputIter result, Compare comp);
template<class ExecutionPolicy, class ForwardIter1, class ForwardIter2,
class ForwardIter>
ForwardIter set_intersection(ExecutionPolicy&& exec,
ForwardIter1 first1, ForwardIter1 last1,
ForwardIter2 first2, ForwardIter2 last2,
ForwardIter result);
template<class ExecutionPolicy, class ForwardIter1, class ForwardIter2,
class ForwardIter, class Compare>
ForwardIter set_intersection(ExecutionPolicy&& exec,
ForwardIter1 first1, ForwardIter1 last1,
ForwardIter2 first2, ForwardIter2 last2,
ForwardIter result, Compare comp);
namespace ranges {
template<class I1, class I2, class O>
using set_intersection_result = in_in_out_result<I1, I2, O>;
template<input_iterator I1, sentinel_for<I1> S1, input_iterator I2,
sentinel_for<I2> S2, weakly_incrementable O, class Comp = ranges::less,
class Proj1 = identity, class Proj2 = identity>
requires mergeable<I1, I2, O, Comp, Proj1, Proj2>
constexpr set_intersection_result<I1, I2, O>
set_intersection(I1 first1, S1 last1, I2 first2, S2 last2, O result,
Comp comp = {}, Proj1 proj1 = {}, Proj2 proj2 = {});
template<input_range R1, input_range R2, weakly_incrementable O,
class Comp = ranges::less, class Proj1 = identity, class Proj2 = identity>
requires mergeable<iterator_t<R1>, iterator_t<R2>, O, Comp, Proj1, Proj2>
constexpr set_intersection_result<borrowed_iterator_t<R1>,
borrowed_iterator_t<R2>, O>
set_intersection(R1&& r1, R2&& r2, O result,
Comp comp = {}, Proj1 proj1 = {}, Proj2 proj2 = {});
}
template<class InputIter1, class InputIter2, class OutputIter>
constexpr OutputIter set_difference(InputIter1 first1, InputIter1 last1,
InputIter2 first2, InputIter2 last2,
OutputIter result);
template<class InputIter1, class InputIter2, class OutputIter, class Compare>
constexpr OutputIter set_difference(InputIter1 first1, InputIter1 last1,
InputIter2 first2, InputIter2 last2,
OutputIter result, Compare comp);
template<class ExecutionPolicy, class ForwardIter1, class ForwardIter2,
class ForwardIter>
ForwardIter set_difference(ExecutionPolicy&& exec,
ForwardIter1 first1, ForwardIter1 last1,
ForwardIter2 first2, ForwardIter2 last2,
ForwardIter result);
template<class ExecutionPolicy, class ForwardIter1, class ForwardIter2,
class ForwardIter, class Compare>
ForwardIter set_difference(ExecutionPolicy&& exec,
ForwardIter1 first1, ForwardIter1 last1,
ForwardIter2 first2, ForwardIter2 last2,
ForwardIter result, Compare comp);
namespace ranges {
template<class I, class O>
using set_difference_result = in_out_result<I, O>;
template<input_iterator I1, sentinel_for<I1> S1, input_iterator I2,
sentinel_for<I2> S2, weakly_incrementable O, class Comp = ranges::less,
class Proj1 = identity, class Proj2 = identity>
requires mergeable<I1, I2, O, Comp, Proj1, Proj2>
constexpr set_difference_result<I1, O>
set_difference(I1 first1, S1 last1, I2 first2, S2 last2, O result,
Comp comp = {}, Proj1 proj1 = {}, Proj2 proj2 = {});
template<input_range R1, input_range R2, weakly_incrementable O,
class Comp = ranges::less, class Proj1 = identity, class Proj2 = identity>
requires mergeable<iterator_t<R1>, iterator_t<R2>, O, Comp, Proj1, Proj2>
constexpr set_difference_result<borrowed_iterator_t<R1>, O>
set_difference(R1&& r1, R2&& r2, O result,
Comp comp = {}, Proj1 proj1 = {}, Proj2 proj2 = {});
}
template<class InputIter1, class InputIter2, class OutputIter>
constexpr OutputIter set_symmetric_difference(InputIter1 first1, InputIter1 last1,
InputIter2 first2, InputIter2 last2,
OutputIter result);
template<class InputIter1, class InputIter2, class OutputIter, class Compare>
constexpr OutputIter set_symmetric_difference(InputIter1 first1, InputIter1 last1,
InputIter2 first2, InputIter2 last2,
OutputIter result, Compare comp);
template<class ExecutionPolicy, class ForwardIter1, class ForwardIter2,
class ForwardIter>
ForwardIter set_symmetric_difference(ExecutionPolicy&& exec,
ForwardIter1 first1, ForwardIter1 last1,
ForwardIter2 first2, ForwardIter2 last2,
ForwardIter result);
template<class ExecutionPolicy, class ForwardIter1, class ForwardIter2,
class ForwardIter, class Compare>
ForwardIter set_symmetric_difference(ExecutionPolicy&& exec,
ForwardIter1 first1, ForwardIter1 last1,
ForwardIter2 first2, ForwardIter2 last2,
ForwardIter result, Compare comp);
namespace ranges {
template<class I1, class I2, class O>
using set_symmetric_difference_result = in_in_out_result<I1, I2, O>;
template<input_iterator I1, sentinel_for<I1> S1, input_iterator I2,
sentinel_for<I2> S2, weakly_incrementable O, class Comp = ranges::less,
class Proj1 = identity, class Proj2 = identity>
requires mergeable<I1, I2, O, Comp, Proj1, Proj2>
constexpr set_symmetric_difference_result<I1, I2, O>
set_symmetric_difference(I1 first1, S1 last1, I2 first2, S2 last2, O result,
Comp comp = {}, Proj1 proj1 = {}, Proj2 proj2 = {});
template<input_range R1, input_range R2, weakly_incrementable O,
class Comp = ranges::less, class Proj1 = identity, class Proj2 = identity>
requires mergeable<iterator_t<R1>, iterator_t<R2>, O, Comp, Proj1, Proj2>
constexpr set_symmetric_difference_result<borrowed_iterator_t<R1>,
borrowed_iterator_t<R2>, O>
set_symmetric_difference(R1&& r1, R2&& r2, O result, Comp comp = {},
Proj1 proj1 = {}, Proj2 proj2 = {});
}
// heap operations
template<class RandomAccessIter>
constexpr void push_heap(RandomAccessIter first, RandomAccessIter last);
template<class RandomAccessIter, class Compare>
constexpr void push_heap(RandomAccessIter first, RandomAccessIter last,
Compare comp);
namespace ranges {
template<random_access_iterator I, sentinel_for<I> S,
class Comp = ranges::less, class Proj = identity>
requires sortable<I, Comp, Proj>
constexpr I push_heap(I first, S last, Comp comp = {}, Proj proj = {});
template<random_access_range R, class Comp = ranges::less, class Proj = identity>
requires sortable<iterator_t<R>, Comp, Proj>
constexpr borrowed_iterator_t<R> push_heap(R&& r, Comp comp = {}, Proj proj = {});
}
template<class RandomAccessIter>
constexpr void pop_heap(RandomAccessIter first, RandomAccessIter last);
template<class RandomAccessIter, class Compare>
constexpr void pop_heap(RandomAccessIter first, RandomAccessIter last,
Compare comp);
namespace ranges {
template<random_access_iterator I, sentinel_for<I> S,
class Comp = ranges::less, class Proj = identity>
requires sortable<I, Comp, Proj>
constexpr I pop_heap(I first, S last, Comp comp = {}, Proj proj = {});
template<random_access_range R, class Comp = ranges::less, class Proj = identity>
requires sortable<iterator_t<R>, Comp, Proj>
constexpr borrowed_iterator_t<R> pop_heap(R&& r, Comp comp = {}, Proj proj = {});
}
template<class RandomAccessIter>
constexpr void make_heap(RandomAccessIter first, RandomAccessIter last);
template<class RandomAccessIter, class Compare>
constexpr void make_heap(RandomAccessIter first, RandomAccessIter last,
Compare comp);
namespace ranges {
template<random_access_iterator I, sentinel_for<I> S,
class Comp = ranges::less, class Proj = identity>
requires sortable<I, Comp, Proj>
constexpr I make_heap(I first, S last, Comp comp = {}, Proj proj = {});
template<random_access_range R, class Comp = ranges::less, class Proj = identity>
requires sortable<iterator_t<R>, Comp, Proj>
constexpr borrowed_iterator_t<R> make_heap(R&& r, Comp comp = {}, Proj proj = {});
}
template<class RandomAccessIter>
constexpr void sort_heap(RandomAccessIter first, RandomAccessIter last);
template<class RandomAccessIter, class Compare>
constexpr void sort_heap(RandomAccessIter first, RandomAccessIter last,
Compare comp);
namespace ranges {
template<random_access_iterator I, sentinel_for<I> S,
class Comp = ranges::less, class Proj = identity>
requires sortable<I, Comp, Proj>
constexpr I sort_heap(I first, S last, Comp comp = {}, Proj proj = {});
template<random_access_range R, class Comp = ranges::less, class Proj = identity>
requires sortable<iterator_t<R>, Comp, Proj>
constexpr borrowed_iterator_t<R> sort_heap(R&& r, Comp comp = {}, Proj proj = {});
}
template<class RandomAccessIter>
constexpr bool is_heap(RandomAccessIter first, RandomAccessIter last);
template<class RandomAccessIter, class Compare>
constexpr bool is_heap(RandomAccessIter first, RandomAccessIter last,
Compare comp);
template<class ExecutionPolicy, class RandomAccessIter>
bool is_heap(ExecutionPolicy&& exec,
RandomAccessIter first, RandomAccessIter last);
template<class ExecutionPolicy, class RandomAccessIter, class Compare>
bool is_heap(ExecutionPolicy&& exec,
RandomAccessIter first, RandomAccessIter last, Compare comp);
namespace ranges {
template<random_access_iterator I, sentinel_for<I> S, class Proj = identity,
indirect_strict_weak_order<projected<I, Proj>> Comp = ranges::less>
constexpr bool is_heap(I first, S last, Comp comp = {}, Proj proj = {});
template<random_access_range R, class Proj = identity,
indirect_strict_weak_order
<projected<iterator_t<R>, Proj>> Comp = ranges::less>
constexpr bool is_heap(R&& r, Comp comp = {}, Proj proj = {});
}
template<class RandomAccessIter>
constexpr RandomAccessIter
is_heap_until(RandomAccessIter first, RandomAccessIter last);
template<class RandomAccessIter, class Compare>
constexpr RandomAccessIter
is_heap_until(RandomAccessIter first, RandomAccessIter last, Compare comp);
template<class ExecutionPolicy, class RandomAccessIter>
RandomAccessIter
is_heap_until(ExecutionPolicy&& exec,
RandomAccessIter first, RandomAccessIter last);
template<class ExecutionPolicy, class RandomAccessIter, class Compare>
RandomAccessIter
is_heap_until(ExecutionPolicy&& exec,
RandomAccessIter first, RandomAccessIter last, Compare comp);
namespace ranges {
template<random_access_iterator I, sentinel_for<I> S, class Proj = identity,
indirect_strict_weak_order<projected<I, Proj>> Comp = ranges::less>
constexpr I is_heap_until(I first, S last, Comp comp = {}, Proj proj = {});
template<random_access_range R, class Proj = identity,
indirect_strict_weak_order
<projected<iterator_t<R>, Proj>> Comp = ranges::less>
constexpr borrowed_iterator_t<R>
is_heap_until(R&& r, Comp comp = {}, Proj proj = {});
}
// minimum and maximum
template<class T> constexpr const T& min(const T& a, const T& b);
template<class T, class Compare>
constexpr const T& min(const T& a, const T& b, Compare comp);
template<class T>
constexpr T min(initializer_list<T> t);
template<class T, class Compare>
constexpr T min(initializer_list<T> t, Compare comp);
namespace ranges {
template<class T, class Proj = identity,
indirect_strict_weak_order<projected<const T*, Proj>> Comp = ranges::less>
constexpr const T& min(const T& a, const T& b, Comp comp = {}, Proj proj = {});
template<copyable T, class Proj = identity,
indirect_strict_weak_order<projected<const T*, Proj>> Comp = ranges::less>
constexpr T min(initializer_list<T> r, Comp comp = {}, Proj proj = {});
template<input_range R, class Proj = identity,
indirect_strict_weak_order
<projected<iterator_t<R>, Proj>> Comp = ranges::less>
requires indirectly_copyable_storable<iterator_t<R>, range_value_t<R>*>
constexpr range_value_t<R> min(R&& r, Comp comp = {}, Proj proj = {});
}
template<class T> constexpr const T& max(const T& a, const T& b);
template<class T, class Compare>
constexpr const T& max(const T& a, const T& b, Compare comp);
template<class T>
constexpr T max(initializer_list<T> t);
template<class T, class Compare>
constexpr T max(initializer_list<T> t, Compare comp);
namespace ranges {
template<class T, class Proj = identity,
indirect_strict_weak_order<projected<const T*, Proj>> Comp = ranges::less>
constexpr const T& max(const T& a, const T& b, Comp comp = {}, Proj proj = {});
template<copyable T, class Proj = identity,
indirect_strict_weak_order<projected<const T*, Proj>> Comp = ranges::less>
constexpr T max(initializer_list<T> r, Comp comp = {}, Proj proj = {});
template<input_range R, class Proj = identity,
indirect_strict_weak_order
<projected<iterator_t<R>, Proj>> Comp = ranges::less>
requires indirectly_copyable_storable<iterator_t<R>, range_value_t<R>*>
constexpr range_value_t<R> max(R&& r, Comp comp = {}, Proj proj = {});
}
template<class T> constexpr pair<const T&, const T&> minmax(const T& a, const T& b);
template<class T, class Compare>
constexpr pair<const T&, const T&> minmax(const T& a, const T& b, Compare comp);
template<class T>
constexpr pair<T, T> minmax(initializer_list<T> t);
template<class T, class Compare>
constexpr pair<T, T> minmax(initializer_list<T> t, Compare comp);
namespace ranges {
template<class T>
using minmax_result = min_max_result<T>;
template<class T, class Proj = identity,
indirect_strict_weak_order<projected<const T*, Proj>> Comp = ranges::less>
constexpr minmax_result<const T&>
minmax(const T& a, const T& b, Comp comp = {}, Proj proj = {});
template<copyable T, class Proj = identity,
indirect_strict_weak_order<projected<const T*, Proj>> Comp = ranges::less>
constexpr minmax_result<T>
minmax(initializer_list<T> r, Comp comp = {}, Proj proj = {});
template<input_range R, class Proj = identity,
indirect_strict_weak_order
<projected<iterator_t<R>, Proj>> Comp = ranges::less>
requires indirectly_copyable_storable<iterator_t<R>, range_value_t<R>*>
constexpr minmax_result<range_value_t<R>>
minmax(R&& r, Comp comp = {}, Proj proj = {});
}
template<class ForwardIter>
constexpr ForwardIter min_element(ForwardIter first, ForwardIter last);
template<class ForwardIter, class Compare>
constexpr ForwardIter min_element(ForwardIter first, ForwardIter last,
Compare comp);
template<class ExecutionPolicy, class ForwardIter>
ForwardIter min_element(ExecutionPolicy&& exec,
ForwardIter first, ForwardIter last);
template<class ExecutionPolicy, class ForwardIter, class Compare>
ForwardIter min_element(ExecutionPolicy&& exec,
ForwardIter first, ForwardIter last,
Compare comp);
namespace ranges {
template<forward_iterator I, sentinel_for<I> S, class Proj = identity,
indirect_strict_weak_order<projected<I, Proj>> Comp = ranges::less>
constexpr I min_element(I first, S last, Comp comp = {}, Proj proj = {});
template<forward_range R, class Proj = identity,
indirect_strict_weak_order
<projected<iterator_t<R>, Proj>> Comp = ranges::less>
constexpr borrowed_iterator_t<R>
min_element(R&& r, Comp comp = {}, Proj proj = {});
}
template<class ForwardIter>
constexpr ForwardIter max_element(ForwardIter first, ForwardIter last);
template<class ForwardIter, class Compare>
constexpr ForwardIter max_element(ForwardIter first, ForwardIter last,
Compare comp);
template<class ExecutionPolicy, class ForwardIter>
ForwardIter max_element(ExecutionPolicy&& exec,
ForwardIter first, ForwardIter last);
template<class ExecutionPolicy, class ForwardIter, class Compare>
ForwardIter max_element(ExecutionPolicy&& exec,
ForwardIter first, ForwardIter last,
Compare comp);
namespace ranges {
template<forward_iterator I, sentinel_for<I> S, class Proj = identity,
indirect_strict_weak_order<projected<I, Proj>> Comp = ranges::less>
constexpr I max_element(I first, S last, Comp comp = {}, Proj proj = {});
template<forward_range R, class Proj = identity,
indirect_strict_weak_order
<projected<iterator_t<R>, Proj>> Comp = ranges::less>
constexpr borrowed_iterator_t<R>
max_element(R&& r, Comp comp = {}, Proj proj = {});
}
template<class ForwardIter>
constexpr pair<ForwardIter, ForwardIter>
minmax_element(ForwardIter first, ForwardIter last);
template<class ForwardIter, class Compare>
constexpr pair<ForwardIter, ForwardIter>
minmax_element(ForwardIter first, ForwardIter last, Compare comp);
template<class ExecutionPolicy, class ForwardIter>
pair<ForwardIter, ForwardIter>
minmax_element(ExecutionPolicy&& exec,
ForwardIter first, ForwardIter last);
template<class ExecutionPolicy, class ForwardIter, class Compare>
pair<ForwardIter, ForwardIter>
minmax_element(ExecutionPolicy&& exec,
ForwardIter first, ForwardIter last, Compare comp);
namespace ranges {
template<class I>
using minmax_element_result = min_max_result<I>;
template<forward_iterator I, sentinel_for<I> S, class Proj = identity,
indirect_strict_weak_order<projected<I, Proj>> Comp = ranges::less>
constexpr minmax_element_result<I>
minmax_element(I first, S last, Comp comp = {}, Proj proj = {});
template<forward_range R, class Proj = identity,
indirect_strict_weak_order
<projected<iterator_t<R>, Proj>> Comp = ranges::less>
constexpr minmax_element_result<borrowed_iterator_t<R>>
minmax_element(R&& r, Comp comp = {}, Proj proj = {});
}
// bounded value
template<class T>
constexpr const T& clamp(const T& v, const T& lo, const T& hi);
template<class T, class Compare>
constexpr const T& clamp(const T& v, const T& lo, const T& hi, Compare comp);
namespace ranges {
template<class T, class Proj = identity,
indirect_strict_weak_order<projected<const T*, Proj>> Comp = ranges::less>
constexpr const T&
clamp(const T& v, const T& lo, const T& hi, Comp comp = {}, Proj proj = {});
}
// lexicographical comparison
template<class InputIter1, class InputIter2>
constexpr bool lexicographical_compare(InputIter1 first1, InputIter1 last1,
InputIter2 first2, InputIter2 last2);
template<class InputIter1, class InputIter2, class Compare>
constexpr bool lexicographical_compare(InputIter1 first1, InputIter1 last1,
InputIter2 first2, InputIter2 last2,
Compare comp);
template<class ExecutionPolicy, class ForwardIter1, class ForwardIter2>
bool lexicographical_compare(ExecutionPolicy&& exec,
ForwardIter1 first1, ForwardIter1 last1,
ForwardIter2 first2, ForwardIter2 last2);
template<class ExecutionPolicy, class ForwardIter1, class ForwardIter2,
class Compare>
bool lexicographical_compare(ExecutionPolicy&& exec,
ForwardIter1 first1, ForwardIter1 last1,
ForwardIter2 first2, ForwardIter2 last2,
Compare comp);
namespace ranges {
template<input_iterator I1, sentinel_for<I1> S1, input_iterator I2,
sentinel_for<I2> S2, class Proj1 = identity, class Proj2 = identity,
indirect_strict_weak_order
<projected<I1, Proj1>, projected<I2, Proj2>> Comp = ranges::less>
constexpr bool
lexicographical_compare(I1 first1, S1 last1, I2 first2, S2 last2,
Comp comp = {}, Proj1 proj1 = {}, Proj2 proj2 = {});
template<input_range R1, input_range R2, class Proj1 = identity,
class Proj2 = identity,
indirect_strict_weak_order
<projected<iterator_t<R1>, Proj1>,
projected<iterator_t<R2>, Proj2>> Comp = ranges::less>
constexpr bool
lexicographical_compare(R1&& r1, R2&& r2, Comp comp = {},
Proj1 proj1 = {}, Proj2 proj2 = {});
}
// three-way comparison algorithms
template<class InputIter1, class InputIter2, class Cmp>
constexpr auto lexicographical_compare_three_way(InputIter1 b1, InputIter1 e1,
InputIter2 b2, InputIter2 e2,
Cmp comp)
-> decltype(comp(*b1, *b2));
template<class InputIter1, class InputIter2>
constexpr auto lexicographical_compare_three_way(InputIter1 b1, InputIter1 e1,
InputIter2 b2, InputIter2 e2);
// permutations
template<class BidirectionalIter>
constexpr bool next_permutation(BidirectionalIter first,
BidirectionalIter last);
template<class BidirectionalIter, class Compare>
constexpr bool next_permutation(BidirectionalIter first,
BidirectionalIter last, Compare comp);
namespace ranges {
template<class I>
using next_permutation_result = in_found_result<I>;
template<bidirectional_iterator I, sentinel_for<I> S, class Comp = ranges::less,
class Proj = identity>
requires sortable<I, Comp, Proj>
constexpr next_permutation_result<I>
next_permutation(I first, S last, Comp comp = {}, Proj proj = {});
template<bidirectional_range R, class Comp = ranges::less, class Proj = identity>
requires sortable<iterator_t<R>, Comp, Proj>
constexpr next_permutation_result<borrowed_iterator_t<R>>
next_permutation(R&& r, Comp comp = {}, Proj proj = {});
}
template<class BidirectionalIter>
constexpr bool prev_permutation(BidirectionalIter first,
BidirectionalIter last);
template<class BidirectionalIter, class Compare>
constexpr bool prev_permutation(BidirectionalIter first,
BidirectionalIter last, Compare comp);
namespace ranges {
template<class I>
using prev_permutation_result = in_found_result<I>;
template<bidirectional_iterator I, sentinel_for<I> S, class Comp = ranges::less,
class Proj = identity>
requires sortable<I, Comp, Proj>
constexpr prev_permutation_result<I>
prev_permutation(I first, S last, Comp comp = {}, Proj proj = {});
template<bidirectional_range R, class Comp = ranges::less, class Proj = identity>
requires sortable<iterator_t<R>, Comp, Proj>
constexpr prev_permutation_result<borrowed_iterator_t<R>>
prev_permutation(R&& r, Comp comp = {}, Proj proj = {});
}
}
类模板 std::ranges::in_fun_result
namespace std::ranges {
template<class I, class F>
struct in_fun_result {
[[no_unique_address]] I in;
[[no_unique_address]] F fun;
template<class I2, class F2>
requires convertible_to<const I&, I2> && convertible_to<const F&, F2>
constexpr operator in_fun_result<I2, F2>() const & {
return {in, fun};
}
template<class I2, class F2>
requires convertible_to<I, I2> && convertible_to<F, F2>
constexpr operator in_fun_result<I2, F2>() && {
return {std::move(in), std::move(fun)};
}
};
}
类模板 std::ranges::in_in_result
namespace std::ranges {
template<class I1, class I2>
struct in_in_result {
[[no_unique_address]] I1 in1;
[[no_unique_address]] I2 in2;
template<class II1, class II2>
requires convertible_to<const I1&, II1> && convertible_to<const I2&, II2>
constexpr operator in_in_result<II1, II2>() const & {
return {in1, in2};
}
template<class II1, class II2>
requires convertible_to<I1, II1> && convertible_to<I2, II2>
constexpr operator in_in_result<II1, II2>() && {
return {std::move(in1), std::move(in2)};
}
};
}
类模板 std::ranges::in_out_result
namespace std::ranges {
template<class I, class O>
struct in_out_result {
[[no_unique_address]] I in;
[[no_unique_address]] O out;
template<class I2, class O2>
requires convertible_to<const I&, I2> && convertible_to<const O&, O2>
constexpr operator in_out_result<I2, O2>() const & {
return {in, out};
}
template<class I2, class O2>
requires convertible_to<I, I2> && convertible_to<O, O2>
constexpr operator in_out_result<I2, O2>() && {
return {std::move(in), std::move(out)};
}
};
}
类模板 std::ranges::in_in_out_result
namespace std::ranges {
template<class I1, class I2, class O>
struct in_in_out_result {
[[no_unique_address]] I1 in1;
[[no_unique_address]] I2 in2;
[[no_unique_address]] O out;
template<class II1, class II2, class OO>
requires convertible_to<const I1&, II1> &&
convertible_to<const I2&, II2> &&
convertible_to<const O&, OO>
constexpr operator in_in_out_result<II1, II2, OO>() const & {
return {in1, in2, out};
}
template<class II1, class II2, class OO>
requires convertible_to<I1, II1> &&
convertible_to<I2, II2> &&
convertible_to<O, OO>
constexpr operator in_in_out_result<II1, II2, OO>() && {
return {std::move(in1), std::move(in2), std::move(out)};
}
};
}
类模板 std::ranges::in_out_out_result
namespace std::ranges {
template<class I, class O1, class O2>
struct in_out_out_result {
[[no_unique_address]] I in;
[[no_unique_address]] O1 out1;
[[no_unique_address]] O2 out2;
template<class II, class OO1, class OO2>
requires convertible_to<const I&, II> &&
convertible_to<const O1&, OO1> &&
convertible_to<const O2&, OO2>
constexpr operator in_out_out_result<II, OO1, OO2>() const & {
return {in, out1, out2};
}
template<class II, class OO1, class OO2>
requires convertible_to<I, II> &&
convertible_to<O1, OO1> &&
convertible_to<O2, OO2>
constexpr operator in_out_out_result<II, OO1, OO2>() && {
return {std::move(in), std::move(out1), std::move(out2)};
}
};
}
类模板 std::ranges::min_max_result
namespace std::ranges {
template<class T>
struct min_max_result {
[[no_unique_address]] T min;
[[no_unique_address]] T max;
template<class T2>
requires convertible_to<const T&, T2>
constexpr operator min_max_result<T2>() const & {
return {min, max};
}
template<class T2>
requires convertible_to<T, T2>
constexpr operator min_max_result<T2>() && {
return {std::move(min), std::move(max)};
}
};
}
类模板 std::ranges::in_found_result
namespace std::ranges {
template<class I>
struct in_found_result {
[[no_unique_address]] I in;
bool found;
template<class I2>
requires convertible_to<const I&, I2>
constexpr operator in_found_result<I2>() const & {
return {in, found};
}
template<class I2>
requires convertible_to<I, I2>
constexpr operator in_found_result<I2>() && {
return {std::move(in), found};
}
};
}
类模板 std::ranges::in_value_result
namespace std::ranges {
template<class I, class T>
struct in_value_result {
[[no_unique_address]] I in;
[[no_unique_address]] T value;
template<class I2, class T2>
requires convertible_to<const I&, I2> && convertible_to<const T&, T2>
constexpr operator in_value_result<I2, T2>() const & {
return {in, value};
}
template<class I2, class T2>
requires convertible_to<I, I2> && convertible_to<T, T2>
constexpr operator in_value_result<I2, T2>() && {
return {std::move(in), std::move(value)};
}
};
}
类模板 std::ranges::out_value_result
namespace std::ranges {
template<class O, class T>
struct out_value_result {
[[no_unique_address]] O out;
[[no_unique_address]] T value;
template<class O2, class T2>
requires convertible_to<const O&, O2> && convertible_to<const T&, T2>
constexpr operator out_value_result<O2, T2>() const & {
return {out, value};
}
template<class O2, class T2>
requires convertible_to<O, O2> && convertible_to<T, T2>
constexpr operator out_value_result<O2, T2>() && {
return {std::move(out), std::move(value)};
}
};
}
C++ 标准库头文件
此头文件是 numeric 库的一部分。
函数
iota
(C++11)
用起始值的连续增量填充一个范围
(函数模板)
ranges::iota
(C++23)
用起始值的连续增量填充一个范围
(算法函数对象)
accumulate
对元素范围求和或折叠
(函数模板)
reduce
(C++17)
类似于 std::accumulate,但顺序不定
(函数模板)
transform_reduce
(C++17)
应用一个可调用对象,然后以无序方式归约
(函数模板)
inner_product
计算两个元素范围的内积
(函数模板)
adjacent_difference
计算范围内相邻元素之间的差值
(函数模板)
partial_sum
计算元素范围的部分和
(函数模板)
inclusive_scan
(C++17)
类似于 std::partial_sum,在第 ith 个和中包含第 ith 个输入元素
(函数模板)
exclusive_scan
(C++17)
类似于 std::partial_sum,在第 ith 个和中排除第 ith 个输入元素
(函数模板)
transform_inclusive_scan
(C++17)
应用一个可调用对象,然后计算包含扫描
(函数模板)
transform_exclusive_scan
(C++17)
应用一个可调用对象,然后计算排除扫描
(函数模板)
gcd
(C++17)
计算两个整数的最大公约数
(函数模板)
lcm
(C++17)
计算两个整数的最小公倍数
(函数模板)
midpoint
(C++20)
两个数字或指针之间的中点
(函数模板)
add_sat
(C++26)
两个整数的饱和加法运算
(函数模板)
sub_sat
(C++26)
两个整数的饱和减法运算
(函数模板)
mul_sat
(C++26)
两个整数的饱和乘法运算
(函数模板)
div_sat
(C++26)
两个整数的饱和除法运算
(函数模板)
saturate_cast
(C++26)
返回一个整数值,该值被钳制到另一种整数类型的范围内
(函数模板)
概要
namespace std {
// accumulate
template<class InputIt, class T>
constexpr T accumulate(InputIt first, InputIt last, T init);
template<class InputIt, class T, class BinaryOperation>
constexpr T accumulate(InputIt first, InputIt last, T init, BinaryOperation binary_op);
// reduce
template<class InputIt>
constexpr typename iterator_traits<InputIt>::value_type
reduce(InputIt first, InputIt last);
template<class InputIt, class T>
constexpr T reduce(InputIt first, InputIt last, T init);
template<class InputIt, class T, class BinaryOperation>
constexpr T reduce(InputIt first, InputIt last, T init, BinaryOperation binary_op);
template<class ExecutionPolicy, class ForwardIt>
typename iterator_traits<ForwardIt>::value_type
reduce(ExecutionPolicy&& exec,
ForwardIt first, ForwardIt last);
template<class ExecutionPolicy, class ForwardIt, class T>
T reduce(ExecutionPolicy&& exec,
ForwardIt first, ForwardIt last, T init);
template<class ExecutionPolicy, class ForwardIt, class T, class BinaryOperation>
T reduce(ExecutionPolicy&& exec,
ForwardIt first, ForwardIt last, T init, BinaryOperation binary_op);
// inner product
template<class InputIt1, class InputIt2, class T>
constexpr T inner_product(InputIt1 first1, InputIt1 last1,
InputIt2 first2, T init);
template<class InputIt1, class InputIt2, class T,
class BinaryOperation1, class BinaryOperation2>
constexpr T inner_product(InputIt1 first1, InputIt1 last1,
InputIt2 first2, T init,
BinaryOperation1 binary_op1,
BinaryOperation2 binary_op2);
// transform reduce
template<class InputIt1, class InputIt2, class T>
constexpr T transform_reduce(InputIt1 first1, InputIt1 last1,
InputIt2 first2,
T init);
template<class InputIt1, class InputIt2, class T,
class BinaryOperation1, class BinaryOperation2>
constexpr T transform_reduce(InputIt1 first1, InputIt1 last1,
InputIt2 first2,
T init,
BinaryOperation1 binary_op1,
BinaryOperation2 binary_op2);
template<class InputIt, class T,
class BinaryOperation, class UnaryOperation>
constexpr T transform_reduce(InputIt first, InputIt last,
T init,
BinaryOperation binary_op, UnaryOperation unary_op);
template<class ExecutionPolicy,
class ForwardIt1, class ForwardIt2, class T>
T transform_reduce(ExecutionPolicy&& exec,
ForwardIt1 first1, ForwardIt1 last1,
ForwardIt2 first2,
T init);
template<class ExecutionPolicy,
class ForwardIt1, class ForwardIt2, class T,
class BinaryOperation1, class BinaryOperation2>
T transform_reduce(ExecutionPolicy&& exec,
ForwardIt1 first1, ForwardIt1 last1,
ForwardIt2 first2,
T init,
BinaryOperation1 binary_op1,
BinaryOperation2 binary_op2);
template<class ExecutionPolicy,
class ForwardIt, class T,
class BinaryOperation, class UnaryOperation>
T transform_reduce(ExecutionPolicy&& exec,
ForwardIt first, ForwardIt last,
T init,
BinaryOperation binary_op, UnaryOperation unary_op);
// partial sum
template<class InputIt, class OutputIt>
constexpr OutputIt partial_sum(InputIt first,
InputIt last,
OutputIt result);
template<class InputIt, class OutputIt, class BinaryOperation>
constexpr OutputIt partial_sum(InputIt first,
InputIt last,
OutputIt result,
BinaryOperation binary_op);
// exclusive scan
template<class InputIt, class OutputIt, class T>
constexpr OutputIt exclusive_scan(InputIt first, InputIt last,
OutputIt result,
T init);
template<class InputIt, class OutputIt, class T, class BinaryOperation>
constexpr OutputIt exclusive_scan(InputIt first, InputIt last,
OutputIt result,
T init, BinaryOperation binary_op);
template<class ExecutionPolicy, class ForwardIt1, class ForwardIt2, class T>
ForwardIt2 exclusive_scan(ExecutionPolicy&& exec,
ForwardIt1 first, ForwardIt1 last,
ForwardIt2 result,
T init);
template<class ExecutionPolicy, class ForwardIt1, class ForwardIt2, class T,
class BinaryOperation>
ForwardIt2 exclusive_scan(ExecutionPolicy&& exec,
ForwardIt1 first, ForwardIt1 last,
ForwardIt2 result,
T init, BinaryOperation binary_op);
// inclusive scan
template<class InputIt, class OutputIt>
constexpr OutputIt inclusive_scan(InputIt first, InputIt last, OutputIt result);
template<class InputIt, class OutputIt, class BinaryOperation>
constexpr OutputIt inclusive_scan(InputIt first, InputIt last,
OutputIt result,
BinaryOperation binary_op);
template<class InputIt, class OutputIt, class BinaryOperation, class T>
constexpr OutputIt inclusive_scan(InputIt first, InputIt last,
OutputIt result,
BinaryOperation binary_op, T init);
template<class ExecutionPolicy, class ForwardIt1, class ForwardIt2>
ForwardIt2 inclusive_scan(ExecutionPolicy&& exec,
ForwardIt1 first, ForwardIt1 last,
ForwardIt2 result);
template<class ExecutionPolicy, class ForwardIt1, class ForwardIt2,
class BinaryOperation>
ForwardIt2 inclusive_scan(ExecutionPolicy&& exec,
ForwardIt1 first, ForwardIt1 last,
ForwardIt2 result,
BinaryOperation binary_op);
template<class ExecutionPolicy, class ForwardIt1, class ForwardIt2,
class BinaryOperation, class T>
ForwardIt2 inclusive_scan(ExecutionPolicy&& exec,
ForwardIt1 first, ForwardIt1 last,
ForwardIt2 result,
BinaryOperation binary_op, T init);
// transform exclusive scan
template<class InputIt, class OutputIt, class T,
class BinaryOperation, class UnaryOperation>
constexpr OutputIt transform_exclusive_scan(InputIt first, InputIt last,
OutputIt result,
T init,
BinaryOperation binary_op,
UnaryOperation unary_op);
template<class ExecutionPolicy,
class ForwardIt1, class ForwardIt2, class T,
class BinaryOperation, class UnaryOperation>
ForwardIt2 transform_exclusive_scan(ExecutionPolicy&& exec,
ForwardIt1 first, ForwardIt1 last,
ForwardIt2 result,
T init,
BinaryOperation binary_op,
UnaryOperation unary_op);
// transform inclusive scan
template<class InputIt, class OutputIt,
class BinaryOperation, class UnaryOperation>
constexpr OutputIt transform_inclusive_scan(InputIt first, InputIt last,
OutputIt result,
BinaryOperation binary_op,
UnaryOperation unary_op);
template<class InputIt, class OutputIt,
class BinaryOperation, class UnaryOperation, class T>
constexpr OutputIt transform_inclusive_scan(InputIt first, InputIt last,
OutputIt result,
BinaryOperation binary_op,
UnaryOperation unary_op,
T init);
template<class ExecutionPolicy,
class ForwardIt1, class ForwardIt2,
class BinaryOperation, class UnaryOperation>
ForwardIt2 transform_inclusive_scan(ExecutionPolicy&& exec,
ForwardIt1 first, ForwardIt1 last,
ForwardIt2 result,
BinaryOperation binary_op,
UnaryOperation unary_op);
template<class ExecutionPolicy,
class ForwardIt1, class ForwardIt2,
class BinaryOperation, class UnaryOperation, class T>
ForwardIt2 transform_inclusive_scan(ExecutionPolicy&& exec,
ForwardIt1 first, ForwardIt1 last,
ForwardIt2 result,
BinaryOperation binary_op,
UnaryOperation unary_op,
T init);
// adjacent difference
template<class InputIt, class OutputIt>
constexpr OutputIt adjacent_difference(InputIt first, InputIt last,
OutputIt result);
template<class InputIt, class OutputIt, class BinaryOperation>
constexpr OutputIt adjacent_difference(InputIt first, InputIt last,
OutputIt result,
BinaryOperation binary_op);
template<class ExecutionPolicy, class ForwardIt1, class ForwardIt2>
ForwardIt2 adjacent_difference(ExecutionPolicy&& exec,
ForwardIt1 first, ForwardIt1 last,
ForwardIt2 result);
template<class ExecutionPolicy, class ForwardIt1, class ForwardIt2,
class BinaryOperation>
ForwardIt2 adjacent_difference(ExecutionPolicy&& exec,
ForwardIt1 first, ForwardIt1 last,
ForwardIt2 result,
BinaryOperation binary_op);
// iota
template<class ForwardIt, class T>
constexpr void iota(ForwardIt first, ForwardIt last, T value);
namespace ranges {
template<class O, class T>
using iota_result = out_value_result<O, T>;
template<input_or_output_iterator O, sentinel_for<O> S, weakly_incrementable T>
requires indirectly_writable<O, const T&>
constexpr iota_result<O, T> iota(O first, S last, T value);
template<weakly_incrementable T, output_range<const T&> R>
constexpr iota_result<borrowed_iterator_t<R>, T> iota(R&& r, T value);
}
// greatest common divisor
template<class M, class N>
constexpr common_type_t<M, N> gcd(M m, N n);
// least common multiple
template<class M, class N>
constexpr common_type_t<M, N> lcm(M m, N n);
// midpoint
template<class T>
constexpr T midpoint(T a, T b) noexcept;
template<class T>
constexpr T* midpoint(T* a, T* b);
// saturation arithmetic
template<class T>
constexpr T add_sat(T x, T y) noexcept; // freestanding
template<class T>
constexpr T sub_sat(T x, T y) noexcept; // freestanding
template<class T>
constexpr T mul_sat(T x, T y) noexcept; // freestanding
template<class T>
constexpr T div_sat(T x, T y) noexcept; // freestanding
template<class T, class U>
constexpr T saturate_cast(U x) noexcept; // freestanding
}