remquo, remquof, remquol
|
|
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Определено в заголовочном файле
<math.h>
|
||
|
float
remquof
(
float
x,
float
y,
int
*
quo
)
;
|
(1) | (начиная с C99) |
|
double
remquo
(
double
x,
double
y,
int
*
quo
)
;
|
(2) | (начиная с C99) |
|
long
double
remquol
(
long
double
x,
long
double
y,
int
*
quo
)
;
|
(3) | (начиная с C99) |
|
Определено в заголовочном файле
<tgmath.h>
|
||
|
#define remquo( x, y, quo )
|
(4) | (начиная с C99) |
remquol
вызывается. В противном случае, если любой аргумент-не-указатель имеет целочисленный тип или тип
double
,
remquo
вызывается. В противном случае
remquof
вызывается.
Содержание |
Параметры
| x, y | - | значения с плавающей запятой |
| quo | - | указатель на целочисленное значение для хранения знака и некоторых битов x / y |
Возвращаемое значение
В случае успеха возвращает остаток от деления с плавающей запятой
x
/
y
, как определено в
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
, прямое обращение к
sin
может привести к значительной погрешности, но если сначала уменьшить аргумент функции с помощью
remquo
, младшие биты частного могут быть использованы для определения знака и октанта результата в пределах периода, в то время как остаток может быть использован для вычисления значения с высокой точностью.
На некоторых платформах эта операция поддерживается аппаратно (и, например, на процессорах Intel,
FPREM1
оставляет ровно 3 бита точности в частном).
Пример
#include <fenv.h> #include <math.h> #include <stdio.h> #ifndef __GNUC__ #pragma STDC FENV_ACCESS ON #endif double cos_pi_x_naive(double x) { const double pi = acos(-1); return cos(pi * x); } // период равен 2, значения (0;0.5) положительные, (0.5;1.5) отрицательные, (1.5,2) положительные double cos_pi_x_smart(double x) { const double pi = acos(-1); int extremum; double rem = remquo(x, 1, &extremum); extremum = (unsigned)extremum % 2; // сохраняем 1 бит для определения ближайшего экстремума return extremum ? -cos(pi * rem) : cos(pi * rem); } int main(void) { printf("cos(pi * 0.25) = %f\n", cos_pi_x_naive(0.25)); printf("cos(pi * 1.25) = %f\n", cos_pi_x_naive(1.25)); printf("cos(pi * 1000000000000.25) = %f\n", cos_pi_x_naive(1000000000000.25)); printf("cos(pi * 1000000000001.25) = %f\n", cos_pi_x_naive(1000000000001.25)); printf("cos(pi * 1000000000000.25) = %f\n", cos_pi_x_smart(1000000000000.25)); printf("cos(pi * 1000000000001.25) = %f\n", cos_pi_x_smart(1000000000001.25)); // обработка ошибок feclearexcept(FE_ALL_EXCEPT); int quo; printf("remquo(+Inf, 1) = %.1f\n", remquo(INFINITY, 1, &quo)); if (fetestexcept(FE_INVALID)) puts(" FE_INVALID raised"); }
Возможный вывод:
cos(pi * 0.25) = 0.707107
cos(pi * 1.25) = -0.707107
cos(pi * 1000000000000.25) = 0.707123
cos(pi * 1000000000001.25) = -0.707117
cos(pi * 1000000000000.25) = 0.707107
cos(pi * 1000000000001.25) = -0.707107
remquo(+Inf, 1) = -nan
FE_INVALID raised
Ссылки
- Стандарт C23 (ISO/IEC 9899:2024):
-
- 7.12.10.3 Функции remquo (стр.: TBD)
-
- 7.25 Обобщённая математика <tgmath.h> (стр.: TBD)
-
- F.10.7.3 Функции remquo (стр.: TBD)
- Стандарт C17 (ISO/IEC 9899:2018):
-
- 7.12.10.3 Функции remquo (стр. 186)
-
- 7.25 Обобщенная математика <tgmath.h> (стр. 272-273)
-
- F.10.7.3 Функции remquo (стр. 385)
- Стандарт C11 (ISO/IEC 9899:2011):
-
- 7.12.10.3 Функции remquo (стр. 255)
-
- 7.25 Обобщенная математика <tgmath.h> (стр. 373-375)
-
- F.10.7.3 Функции remquo (стр. 529)
- Стандарт C99 (ISO/IEC 9899:1999):
-
- 7.12.10.3 Функции remquo (стр. 236)
-
- 7.22 Обобщенная математика <tgmath.h> (стр. 335-337)
-
- F.9.7.3 Функции remquo (стр. 465)
Смотрите также
|
(C99)
|
вычисляет частное и остаток от целочисленного деления
(функция) |
|
(C99)
(C99)
|
вычисляет остаток от операции деления с плавающей запятой
(функция) |
|
(C99)
(C99)
(C99)
|
вычисляет знаковый остаток от операции деления с плавающей запятой
(функция) |
|
C++ documentation
для
remquo
|
|