Почему деление модуля (%) работает только с целыми числами? - PullRequest
73 голосов
/ 24 мая 2011

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

При заданной периодической функции (например, sin)и компьютерная функция, которая может вычислить его только в пределах периода (например, [-π, π]), создать функцию, которая может обрабатывать любой ввод.

«Очевидное» решение - это что-то вроде:

#include <cmath>

float sin(float x){
    return limited_sin((x + M_PI) % (2 *M_PI) - M_PI);
}

Почему это не работает?Я получаю эту ошибку:

error: invalid operands of types double and double to binary operator %

Интересно, что она работает в Python:

def sin(x):
    return limited_sin((x + math.pi) % (2 * math.pi) - math.pi)

Ответы [ 9 ]

72 голосов
/ 24 мая 2011

Потому что обычное математическое понятие «остаток» применимо только к целочисленному делению.т.е. деление, которое требуется для генерации целочисленного отношения.

Чтобы распространить понятие «остаток» на действительные числа, необходимо ввести новый тип «гибридной» операции, которая генерирует целое число частное для реальных операндов.Базовый язык C не поддерживает такую ​​операцию, но он предоставляется в виде стандартной библиотеки fmod, а также функции remainder в C99.(Обратите внимание, что эти функции не одинаковы и имеют некоторые особенности. В частности, они не соответствуют правилам округления целочисленного деления.)

47 голосов
/ 24 мая 2011

Вы ищете fmod () .

Я думаю, чтобы более конкретно ответить на ваш вопрос, в старых языках оператор % был определен как целочисленное модульное деление и вВ более новых языках они решили расширить определение оператора.

РЕДАКТИРОВАТЬ: Если бы я решил, почему, я бы сказал, что это потому, что идея модульной арифметики берет свое начало в теории чиселимеет дело конкретно с целыми числами.

15 голосов
/ 24 мая 2011

Я не могу сказать за , конечно, , но я думаю, это в основном историческое.Многие ранние компиляторы Си вообще не поддерживали плавающую точку.Он был добавлен позже, и даже тогда не так полностью - в основном был добавлен тип данных и большинство примитивных операций, поддерживаемых в языке, но все остальное оставлено в стандартной библиотеке.

12 голосов
/ 24 мая 2011

Оператор по модулю % в C и C ++ определен для двух целых чисел, однако есть функция fmod(), доступная для использования с двойными значениями.

7 голосов
/ 10 июля 2013

Ограничения указаны в стандартах:

C11 (ISO / IEC 9899: 201x) §6.5.5 Мультипликативные операторы

Каждый из операндовдолжен иметь арифметический тип.Операнды оператора% должны иметь целочисленный тип.

C ++ 11 (ISO / IEC 14882: 2011) §5.6 Мультипликативные операторы

Операнды * и / должны иметь арифметический или перечислимый тип;операнды% должны иметь целочисленный тип или тип перечисления.Обычные арифметические преобразования выполняются над операндами и определяют тип результата.

Решение состоит в том, чтобы использовать fmod, именно поэтому операнды % ограничены целочисленным типомво-первых, согласно Обоснование C99 §6.5.5 Мультипликативные операторы :

Комитет C89 отклонил расширение оператора% для работы с плавающими типамикак такое использование будет дублировать средство, предоставленное fmod

4 голосов
/ 24 мая 2011

попробуй fmod

2 голосов
/ 28 октября 2014

Оператор % не работает в C ++, когда вы пытаетесь найти остаток от двух чисел, оба типа Float или Double.

Следовательно, вы можете попробовать использовать функцию fmod из math.h / cmath.h или использовать следующие строки кода, чтобы избежать использования этого заголовочного файла:

float sin(float x) {
 float temp;
 temp = (x + M_PI) / ((2 *M_PI) - M_PI);
 return limited_sin((x + M_PI) - ((2 *M_PI) - M_PI) * temp ));

}

2 голосов
/ 24 мая 2011

Оператор% дает вам REMAINDER (другое имя для модуля) числа. Для C / C ++ это определено только для целочисленных операций. Python немного шире и позволяет вам получить остаток от числа с плавающей запятой на остаток от того, сколько раз число может быть разделено на него:

>>> 4 % math.pi
0.85840734641020688
>>> 4 - math.pi
0.85840734641020688
>>> 
0 голосов
/ 08 февраля 2019

"Математическое понятие арифметики по модулю работает и для значений с плавающей запятой, и это одна из первых проблем, которую Дональд Кнут обсуждает в своей классической книге" Искусство компьютерного программирования "(том I). То есть когда-то это были базовые знания.«

Оператор модуля с плавающей запятой определяется следующим образом:

m = num - iquot*den ; where iquot = int( num/den )

Как указано, запрет оператора% на числа с плавающей запятой, похоже, связан со стандартами.CRTL предоставляет «fmod» и, как правило, «остаток» для выполнения% на числах fp.Разница между этими двумя заключается в том, как они обрабатывают промежуточное округление «iquot».

«остаток» использует округление до ближайшего, а «fmod» использует простое усечение.

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

С наилучшими пожеланиями

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...