Namensräume
Varianten
Aktionen

std::remquo, std::remquof, std::remquol

Von cppreference.com
< cpp‎ | numeric‎ | math
 
 
 
 
Definiert in der Header-Datei <cmath>
(1)
float       remquo ( float x, float y, int* quo );

double      remquo ( double x, double y, int* quo );

long double remquo ( long double x, long double y, int* quo );
(seit C++11)
(bis C++23)
constexpr /* gleitkommazahl-Typ */

            remquo ( /* Gleitkommatyp */ x,

                     /* Gleitkommatyp */ y, int* quo );
(seit C++23)
float       remquof( float x, float y, int* quo );
(2) (seit C++11)
(constexpr seit C++23)
long double remquol( long double x, long double y, int* quo );
(3) (seit C++11)
(constexpr seit C++23)
Definiert in der Header-Datei <cmath>
template< class Arithmetic1, class Arithmetic2 >

/* common-floating-point-type */

    remquo( Arithmetic1 x, Arithmetic2 y, int* quo );
(A) (seit C++11)
(constexpr seit C++23)
1-3) Berechnet den Gleitkomma-Rest der Division x / y so, wie es die Funktion std::remainder() tut. Zusätzlich werden das Vorzeichen und mindestens die letzten drei Bits von x / y in quo gespeichert, ausreichend, um den Oktanten des Ergebnisses innerhalb einer Periode zu bestimmen. Die Bibliothek stellt Überladungen von std::remquo für alle cv-unqualifizierten Gleitkommatypen als Typ der Parameter x und y bereit.(seit C++23)
A) Zusätzliche Überladungen werden für alle anderen Kombinationen von arithmetischen Typen bereitgestellt.

Inhalt

[edit] Parameter

x, y - Gleitkomma- oder Ganzzahlwerte
quo - Zeiger auf int, um das Vorzeichen und einige Bits von x / y zu speichern

[edit] Rückgabewert

Bei Erfolg gibt der Gleitkomma-Rest der Division x / y zurück, wie in std::remainder definiert, und speichert in *quo das Vorzeichen und mindestens drei der niedrigsten Bits von x / y (formal wird ein Wert gespeichert, dessen Vorzeichen das Vorzeichen von x / y ist und dessen Betrag kongruent modulo 2n
zum Betrag des ganzzahligen Quotienten von x / y ist, wobei n eine implementierungsdefinierte ganze Zahl größer oder gleich 3 ist).

Wenn y Null ist, ist der Wert, der in *quo gespeichert wird, undefiniert.

Wenn ein Domänenfehler auftritt, wird ein implementierungsabhängiger Wert zurückgegeben (NaN, wo unterstützt).

Wenn ein Bereichsfehler aufgrund von Unterlauf auftritt, wird das korrekte Ergebnis zurückgegeben, wenn Subnormale unterstützt werden.

Wenn y Null ist, aber kein Bereichsfehler auftritt, wird Null zurückgegeben.

[edit] Fehlerbehandlung

Fehler werden wie in math_errhandling beschrieben gemeldet.

Ein Domänenfehler kann auftreten, wenn y null ist.

Wenn die Implementierung IEEE-Gleitkomma-Arithmetik (IEC 60559) unterstützt,

  • Der aktuelle Rundungsmodus hat keinen Einfluss.
  • FE_INEXACT wird nie ausgelöst.
  • Wenn x ±∞ ist und y keine NaN ist, wird NaN zurückgegeben und FE_INVALID ausgelöst.
  • Wenn y ±0 ist und x keine NaN ist, wird NaN zurückgegeben und FE_INVALID ausgelöst.
  • Wenn entweder x oder y NaN ist, wird NaN zurückgegeben.

[edit] Anmerkungen

POSIX erfordert, dass ein Bereichsfehler auftritt, wenn x unendlich ist oder y Null ist.

Diese Funktion ist nützlich bei der Implementierung periodischer Funktionen mit exakt darstellbarer Periode als Gleitkommawert: Bei der Berechnung von sin(πx) für ein sehr großes x kann der direkte Aufruf von std::sin zu einem großen Fehler führen. Wenn jedoch das Funktionsargument zuerst mit std::remquo reduziert wird, können die niedrigwertigen Bits des Quotienten verwendet werden, um das Vorzeichen und den Oktanten des Ergebnisses innerhalb der Periode zu bestimmen, während der Rest zur hochpräzisen Berechnung des Wertes verwendet werden kann.

Auf einigen Plattformen wird diese Operation von der Hardware unterstützt (und beispielsweise auf Intel-CPUs hinterlässt FPREM1 bei Abschluss genau 3 Bits Präzision im Quotienten).

Die zusätzlichen Überladungen müssen nicht exakt wie (A) angegeben werden. Sie müssen nur ausreichen, um sicherzustellen, dass für ihr erstes Argument num1 und ihr zweites Argument num2

  • Wenn num1 oder num2 vom Typ long double ist, hat std::remquo(num1, num2, quo) denselben Effekt wie std::remquo(static_cast<long double>(num1),
                static_cast<long double>(num2), quo)
    .
  • Andernfalls, wenn num1 und/oder num2 vom Typ double oder einem ganzzahligen Typ ist, hat std::remquo(num1, num2, quo) denselben Effekt wie std::remquo(static_cast<double>(num1),
                static_cast<double>(num2), quo)
    .
  • Andernfalls, wenn num1 oder num2 vom Typ float ist, hat std::remquo(num1, num2, quo) denselben Effekt wie std::remquo(static_cast<float>(num1),
                static_cast<float>(num2), quo)
    .
(bis C++23)

Wenn num1 und num2 arithmetische Typen haben, hat std::remquo(num1, num2, quo) denselben Effekt wie std::remquo(static_cast</*gemeinsamer_gleitkommatyp*/>(num1),
            static_cast</*gemeinsamer_gleitkommatyp*/>(num2), quo)
, wobei /*gemeinsamer_gleitkommatyp*/ der Gleitkommatyp mit dem höchsten Gleitkomma-Konversionsrang und dem höchsten Gleitkomma-Konversions-Subrang zwischen den Typen von num1 und num2 ist; ganze Zahlen werden so betrachtet, als hätten sie denselben Gleitkomma-Konversionsrang wie double.

Wenn kein solcher Gleitkommazahltyp mit dem höchsten Rang und Subrang existiert, dann führt die Überladungsauflösung nicht zu einem nutzbaren Kandidaten aus den bereitgestellten Überladungen.

(seit C++23)

[edit] Beispiel

#include <cfenv>
#include <cmath>
#include <iostream>
 
#ifndef __GNUC__
#pragma STDC FENV_ACCESS ON
#endif
 
const double pi = std::acos(-1); // or std::numbers::pi since C++20
 
double cos_pi_x_naive(double x)
{
    return std::cos(pi * x);
}
 
// the period is 2, values are (0;0.5) positive, (0.5;1.5) negative, (1.5,2) positive
double cos_pi_x_smart(double x)
{
    int quadrant;
    double rem = std::remquo(x, 1, &quadrant);
    quadrant = static_cast<unsigned>(quadrant) % 2; // The period is 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';
 
    // error handling
    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";
}

Mögliche Ausgabe

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

[edit] Siehe auch

berechnet Quotient und Rest der ganzzahligen Division
(Funktion) [bearbeiten]
(C++11)(C++11)
Rest der Gleitkommadivisionsoperation
(Funktion) [bearbeiten]
(C++11)(C++11)(C++11)
Vorzeichenbehafteter Rest der Divisionsoperation
(Funktion) [bearbeiten]
C-Dokumentation für remquo