std:: remquo, std:: remquof, std:: remquol
|
Определено в заголовочном файле
<cmath>
|
||
| (1) | ||
|
float
remquo
(
float
x,
float
y,
int
*
quo
)
;
double
remquo
(
double
x,
double
y,
int
*
quo
)
;
|
(начиная с C++11)
(до C++23) |
|
|
constexpr
/* floating-point-type */
remquo
(
/* floating-point-type */
x,
|
(начиная с C++23) | |
|
float
remquof
(
float
x,
float
y,
int
*
quo
)
;
|
(2) |
(начиная с C++11)
(constexpr начиная с C++23) |
|
long
double
remquol
(
long
double
x,
long
double
y,
int
*
quo
)
;
|
(3) |
(начиная с C++11)
(constexpr начиная с C++23) |
|
Определено в заголовочном файле
<cmath>
|
||
|
template
<
class
Arithmetic1,
class
Arithmetic2
>
/* common-floating-point-type */
|
(A) |
(начиная с C++11)
(constexpr начиная с C++23) |
std::remquo
для всех типов с плавающей точкой без cv-квалификаторов в качестве типа параметров
x
и
y
.
(since C++23)
Содержание |
Параметры
| x, y | - | значения с плавающей точкой или целочисленные |
| quo | - | указатель на int для хранения знака и некоторых битов x / y |
Возвращаемое значение
В случае успеха возвращает остаток от деления с плавающей запятой
x
/
y
, как определено в
std::remainder
, и сохраняет в
*
quo
знак и как минимум три младших бита
x
/
y
(формально, сохраняет значение, знак которого соответствует знаку
x
/
y
, а величина конгруэнтна
по модулю 2
n
величине целочисленного частного от
x
/
y
, где
n
— определяемое реализацией целое число, большее или равное
3
).
Если y равен нулю, значение, хранящееся в * quo , не определено.
Если происходит ошибка области определения, возвращается значение, определяемое реализацией (NaN, если поддерживается).
Если происходит ошибка диапазона из-за потери значимости, возвращается корректный результат при поддержке субнормальных чисел.
Если y равен нулю, но ошибка домена не возникает, возвращается ноль.
Обработка ошибок
Ошибки сообщаются, как указано в math_errhandling .
Ошибка домена может возникнуть, если y равен нулю.
Если реализация поддерживает арифметику с плавающей запятой IEEE (IEC 60559),
- Текущий режим округления не оказывает влияния.
- FE_INEXACT никогда не возбуждается.
- Если x равен ±∞ и y не является NaN, возвращается NaN и возбуждается FE_INVALID .
- Если y равен ±0 и x не является NaN, возвращается NaN и возбуждается FE_INVALID .
- Если любой из аргументов x или y является NaN, возвращается NaN.
Примечания
POSIX требует возникновения ошибки домена, если x является бесконечным или y равен нулю.
Эта функция полезна при реализации периодических функций с периодом, точно представимым в виде значения с плавающей запятой: при вычислении
sin(πx)
для очень большого
x
, прямое обращение к
std::sin
может привести к значительной погрешности, но если сначала уменьшить аргумент функции с помощью
std::remquo
, младшие биты частного могут быть использованы для определения знака и октанта результата в пределах периода, в то время как остаток может быть использован для вычисления значения с высокой точностью.
На некоторых платформах эта операция поддерживается аппаратно (и, например, на процессорах Intel,
FPREM1
оставляет ровно 3 бита точности в частном при завершении).
Дополнительные перегрузки не обязаны быть предоставлены в точности как (A) . Они должны быть лишь достаточными для обеспечения того, чтобы для их первого аргумента num1 и второго аргумента num2 :
|
(до C++23) |
|
Если
num1
и
num2
имеют арифметические типы, то
std
::
remquo
(
num1, num2, quo
)
имеет тот же эффект, что и
std
::
remquo
(
static_cast
<
/*common-floating-point-type*/
>
(
num1
)
,
Если такого типа с плавающей запятой с наибольшим рангом и подрангом не существует, то разрешение перегрузки не приводит к пригодному кандидату из предоставленных перегрузок. |
(начиная с C++23) |
Пример
#include <cfenv> #include <cmath> #include <iostream> #ifndef __GNUC__ #pragma STDC FENV_ACCESS ON #endif const double pi = std::acos(-1); // или std::numbers::pi начиная с C++20 double cos_pi_x_naive(double x) { return std::cos(pi * x); } // период равен 2, значения (0;0.5) положительные, (0.5;1.5) отрицательные, (1.5,2) положительные double cos_pi_x_smart(double x) { int quadrant; double rem = std::remquo(x, 1, &quadrant); quadrant = static_cast<unsigned>(quadrant) % 2; // Период равен 2. return quadrant == 0 ? std::cos(pi * rem) : -std::cos(pi * rem); } int main() { std::cout << std::showpos << "naive:\n" << " cos(pi * 0.25) = " << cos_pi_x_naive(0.25) << '\n' << " cos(pi * 1.25) = " << cos_pi_x_naive(1.25) << '\n' << " cos(pi * 2.25) = " << cos_pi_x_naive(2.25) << '\n' << "smart:\n" << " cos(pi * 0.25) = " << cos_pi_x_smart(0.25) << '\n' << " cos(pi * 1.25) = " << cos_pi_x_smart(1.25) << '\n' << " cos(pi * 2.25) = " << cos_pi_x_smart(2.25) << '\n' << "naive:\n" << " cos(pi * 1000000000000.25) = " << cos_pi_x_naive(1000000000000.25) << '\n' << " cos(pi * 1000000000001.25) = " << cos_pi_x_naive(1000000000001.25) << '\n' << "smart:\n" << " cos(pi * 1000000000000.25) = " << cos_pi_x_smart(1000000000000.25) << '\n' << " cos(pi * 1000000000001.25) = " << cos_pi_x_smart(1000000000001.25) << '\n'; // обработка ошибок std::feclearexcept(FE_ALL_EXCEPT); int quo; std::cout << "remquo(+Inf, 1) = " << std::remquo(INFINITY, 1, &quo) << '\n'; if (fetestexcept(FE_INVALID)) std::cout << " FE_INVALID raised\n"; }
Возможный вывод:
naive: cos(pi * 0.25) = +0.707107 cos(pi * 1.25) = -0.707107 cos(pi * 2.25) = +0.707107 smart: cos(pi * 0.25) = +0.707107 cos(pi * 1.25) = -0.707107 cos(pi * 2.25) = +0.707107 naive: cos(pi * 1000000000000.25) = +0.707123 cos(pi * 1000000000001.25) = -0.707117 smart: cos(pi * 1000000000000.25) = +0.707107 cos(pi * 1000000000001.25) = -0.707107 remquo(+Inf, 1) = -nan FE_INVALID raised
Смотрите также
|
(C++11)
|
вычисляет частное и остаток от целочисленного деления
(функция) |
|
(C++11)
(C++11)
|
остаток от операции деления чисел с плавающей точкой
(функция) |
|
(C++11)
(C++11)
(C++11)
|
знаковый остаток от операции деления
(функция) |
|
C documentation
для
remquo
|
|