Подтвердить что ты не робот

Почему модульное деление (%) работает только с целыми числами?

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

Для периодической функции (например, 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)
4b9b3361

Ответ 1

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

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

Ответ 2

Вы ищете fmod().

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

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

Ответ 3

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

Ответ 4

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

Ответ 5

Ограничения в стандартах:

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

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

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

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

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

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

Ответ 6

попробуйте fmod

Ответ 7

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

>>> 4 % math.pi
0.85840734641020688
>>> 4 - math.pi
0.85840734641020688
>>> 

Ответ 8

Оператор % не работает на С++, когда вы пытаетесь найти остаток из двух чисел, которые являются как типом 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 ));

}

Ответ 9

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

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

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

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

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

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

С уважением