Инверсия fmod

Если у меня есть следующее на С++:

fmod(x, n) = o

как восстановить значение x из o? когда значение n известно.

Я пытался использовать обычный мод, где

a%b=c 
if a>=b then 
b+c -> a 
else 
c -> a 

но это не работает, когда мы используем числа с плавающей запятой

Невозможно, информация утеряна

harold 30.05.2023 13:16

Вы также не можете инвертировать %. Например, n % 2 = 0 для всех четных чисел — единственная информация, которую вы получите, это n == k * 2 для некоторого неизвестного k. Кроме того, ваш метод основан на уже известном значении a, так что...

molbdnilo 30.05.2023 13:25
double frestore_x(double x, double n, double o) { return x; }
Eljay 30.05.2023 13:33

Вы ищете версию std::div с плавающей запятой?

Bob__ 30.05.2023 13:41

Вы не можете. Любые указанные значения n и o соответствуют бесконечному количеству значений x. Вы можете получить ОДНО из возможных значений x (например, как n + o). В общем случае x будет одним из значений n + i * o, где i — любое целочисленное значение. Было бы проще просто сохранить исходное значение x перед вычислением fmod(x, n).

Peter 30.05.2023 14:03

Модуль получается как остаток после деления. Чтобы вернуться назад, вам также нужен результат деления, поэтому (для целочисленной арифметики) q = x/n, r = x - qn, где r - x mod n, а чтобы вернуться назад, x = r + qn.

Simon Goater 30.05.2023 14:23

Есть ли у x какой-то ограниченный набор значений, которые он принимает? У вас есть способ проверить правильность данного предположения x?

President James K. Polk 30.05.2023 18:01
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
7
115
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

fmod(x,10) = 0

Это учитывается для каждого целого числа, заканчивающегося нулем, например 0, -10, 20, -30,..., 100, -110, 120, -130,..., 200, -210, 220, -230. , ..., 300, -310, 320, -330, ..., 1000, -1010, 1020, -1030, ..., 1100, -1110, 1120, -1130, ... (вы также встречаются ±123456789876543210 и ±98765432123456890 и многие-многие другие) :-)

Вы понимаете, почему на ваш вопрос не может быть ответа? :-)

То же самое на самом деле относится и к интегралам, их так много/слишком много a, имеющих a % b == c...

Aconcagua 30.05.2023 13:24
Ответ принят как подходящий

Из этой ссылки на std::fmod:

Остаток операции деления x / y с плавающей запятой, вычисленный этой функцией, точно равен значению x - rem * y, где rem — это x / y с усеченной дробной частью.

[Emphasis mine]

Поскольку дробная часть усекается, невозможно вернуть исходное значение.

И это до вовлечения этого.

«Это до того, как это связано с этим». (это пределы математики FP) , хотя это и является общим трюизмом, здесь не обязательно применимо. Хороший fmod() не должен возвращать потерю точности. результат точен по определению, даже если промежуточные операции x/y, ... имеют неточное представление

chux - Reinstate Monica 30.05.2023 17:28

Далее я предполагаю вычисление double, где double отображается в формате IEEE-754 binary64.

Любое общее деление дает две порции информации: частное и остаток. fmod (a, b) возвращает остаток a / b, когда неявное частное преобразуется в целое число с округлением до нуля (усечение). Исходное делимое может быть вычислено из делителя b, усеченного частного и остатка, возвращаемого fmod(), при условии, что частное точно представимо в виде double. Без частного недостаточно информации для повторного вычисления дивиденда.

Поскольку операнд double обеспечивает 52 сохраненных значащих (мантиссы) бита, частное в общем случае точно представимо только в том случае, если разница двоичных показателей делимого и делителя не превышает 52. Очевидно, нам нужно избегать делимых и делителей, которые равны бесконечности. или NaN, и делитель не может быть равен нулю. Пересчет дивиденда как (частное * делитель + остаток) должен выполняться с однократным округлением, поэтому необходимо использовать плавное умножение-сложение (FMA).

Следующая программа демонстрирует успешный пересчет дивиденда при указанных ограничениях. Обратите внимание, что для достижения предполагаемой функциональности fdiv_rz() требуется настроить компилятор для самого строгого соблюдения IEEE-754. В противном случае компилятор может рассматривать операцию деления как независимую от вызовов fesetround(), в результате чего порядок операций будет изменен таким образом, что деление больше не будет зажато между вызовами fesetround() по мере необходимости. Из того, что я вижу, это особенно влияет на gcc, тогда как clang по умолчанию ведет себя лучше. Я использовал компилятор Intel для создания этого кода, который позволяет легко управлять поведением с плавающей запятой. В частности, я скомпилировал с icl /Qstd=c++11 /Ox /QxHOST /W4 /fp:strict fdiv_fmod.cpp.

#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <math.h>
#include <fenv.h>

#define N (2000000000)  // number of random test cases

/* divide a by b, rounding result towards zero */
double fdiv_rz (double a, double b) 
{
    double quot;
    int curr_mode = fegetround ();
    fesetround (FE_TOWARDZERO);
    quot = a / b;
    fesetround (curr_mode);
    return quot;
}

/* reinterpret 64-bit unsigned integer as an IEEE-754 binary64 */
double uint64_as_double (uint64_t a)
{
    double r;
    memcpy (&r, &a, sizeof r);
    return r;
}

/*
  https://groups.google.com/forum/#!original/comp.lang.c/qFv18ql_WlU/IK8KGZZFJx4J
  From: geo <[email protected]>
  Newsgroups: sci.math,comp.lang.c,comp.lang.fortran
  Subject: 64-bit KISS RNGs
  Date: Sat, 28 Feb 2009 04:30:48 -0800 (PST)

  This 64-bit KISS RNG has three components, each nearly
  good enough to serve alone.    The components are:
  Multiply-With-Carry (MWC), period (2^121+2^63-1)
  Xorshift (XSH), period 2^64-1
  Congruential (CNG), period 2^64
*/
static uint64_t kiss64_x = 1234567890987654321ULL;
static uint64_t kiss64_c = 123456123456123456ULL;
static uint64_t kiss64_y = 362436362436362436ULL;
static uint64_t kiss64_z = 1066149217761810ULL;
static uint64_t kiss64_t;
#define MWC64  (kiss64_t = (kiss64_x << 58) + kiss64_c, \
                kiss64_c = (kiss64_x >> 6), kiss64_x += kiss64_t, \
                kiss64_c += (kiss64_x < kiss64_t), kiss64_x)
#define XSH64  (kiss64_y ^= (kiss64_y << 13), kiss64_y ^= (kiss64_y >> 17), \
                kiss64_y ^= (kiss64_y << 43))
#define CNG64  (kiss64_z = 6906969069ULL * kiss64_z + 1234567ULL)
#define KISS64 (MWC64 + XSH64 + CNG64)

int main (void)
{
    double a, b, t, quot, rem;
    int expa, expb;

    for (int i = 0; i < N; i++) {
        do {
            a = uint64_as_double (KISS64);
        } while (isinf (a) || isnan (a));
        (void)frexp (a, &expa);
        do {
            b = uint64_as_double (KISS64);
            (void)frexp (b, &expb);
        } while ((b == 0) || isinf (b) || isnan (b) || (abs (expa - expb) > 52));
        
        quot = trunc (fdiv_rz (a, b));
        rem  = fmod (a, b);
        t = (fabs (quot) < 1.0) ? rem : fma (quot, b, rem);

        if (t != a) {
            printf ("a=% 23.13a  b=% 23.13a  quot=% 23.13a  rem=%23.13a  t=% 23.13a\n",
                    a, b, quot, rem, t);
            return EXIT_FAILURE;
        }
    }
    printf ("test passed\n");
    return EXIT_SUCCESS;
}

Идея, которую вы продемонстрировали, кажется, работает. По крайней мере, с целыми числами он работает нормально. Тем не менее, код кажется немного запутанным. Есть много линий, которые кажутся немного сложными.

abdullah35 01.06.2023 18:29

Что я понял из вашего ответа, так это то, смогли ли мы рассчитать напоминание и частное более точным способом. А потом применил частное * делитель + напоминание работало бы нормально..

abdullah35 01.06.2023 18:31

Другие вопросы по теме

Похожие вопросы