web-dev-qa-db-fra.com

Pourquoi la division de module (%) ne fonctionne-t-elle qu'avec des nombres entiers?

J'ai récemment rencontré un problème qui pourrait être facilement résolu en utilisant la division de module, mais l'entrée était un float:

Étant donné une fonction périodique (par exemple, sin) et une fonction informatique qui ne peut la calculer que dans la plage de périodes (par exemple, [-π, π]), créez une fonction capable de gérer toute entrée.

La solution "évidente" est quelque chose comme:

#include <cmath>

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

Pourquoi ça ne marche pas? Je reçois cette erreur:

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

Fait intéressant, cela fonctionne en Python:

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

Parce que la notion mathématique normale de "reste" ne s'applique qu'à la division entière. c'est-à-dire la division requise pour générer un quotient entier.

Afin d'étendre le concept de "reste" aux nombres réels, vous devez introduire un nouveau type d'opération "hybride" qui générerait un quotient integer pour des opérandes real. Ce langage ne prend pas en charge cette opération, mais il est fourni sous forme de bibliothèque standard fmod function, ainsi que - remainder function en C99. (Notez que ces fonctions ne sont pas les mêmes et présentent certaines particularités. En particulier, elles ne suivent pas les règles d'arrondi de la division entière.)

71
AnT

Vous recherchez fmod () .

Je suppose que pour répondre plus spécifiquement à votre question, dans les langues plus anciennes, l'opérateur % était simplement défini comme une division modulaire entière et dans les langues plus récentes, ils ont décidé d'élargir la définition de l'opérateur.

EDIT: Si je devais parier, je dirais que c'est parce que l'idée de l'arithmétique modulaire trouve son origine dans la théorie des nombres et concerne spécifiquement les entiers.

46
Doug Stephen

Je ne peux pas vraiment dire pour bien sûr , mais je suppose que c'est surtout historique. Quelques premiers compilateurs C ne supportaient pas du tout les virgules flottantes. Il a été ajouté plus tard, et même alors pas aussi complètement - le type de données a été principalement ajouté et les opérations primitives primitives supportées dans le langage, mais tout le reste a été laissé à la bibliothèque standard.

15
Jerry Coffin

L'opérateur modulo % en C et C++ est défini pour deux entiers. Toutefois, une fonction fmod() est disponible pour une utilisation avec des doubles.

12
Mark Elliot

Les contraintes sont dans les standards:

C11 (ISO/IEC 9899: 201x) §6.5.5 Opérateurs multiplicatifs

Chacun des opérandes doit avoir un type arithmétique. Les opérandes de l'opérateur% doivent avoir un type entier.

C++ 11 (ISO/IEC 14882: 2011) §5.6 Opérateurs multiplicatifs

Les opérandes de * et/doivent être de type arithmétique ou énumération; les opérandes de% doivent faire partie intégrante ou énumération type. Les conversions arithmétiques habituelles sont effectuées sur les opérandes et déterminent le type du résultat.

La solution consiste à utiliser fmod, ce qui explique pourquoi les opérandes de % sont d'abord limités au type entier, selon C99 Rationale §6.5.5 Opérateurs multiplicatifs:

Le Comité C89 a rejeté l’extension de l’opérateur% aux travaux sur les types flottants, car une telle utilisation ferait double emploi avec le service fourni par fmod.

7
Yu Hao

essayez fmod

4
justin

L'opérateur % ne fonctionne pas en C++ lorsque vous essayez de trouver le reste de deux nombres de type Float ou Double.

Par conséquent, vous pouvez essayer d'utiliser la fonction fmod de math.h/cmath.h ou utiliser ces lignes de code pour éviter d'utiliser ce fichier d'en-tête:

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
Shank

L'opérateur% vous donne un REMAINDER (un autre nom pour le module) d'un nombre. Pour C/C++, cela n'est défini que pour les opérations sur les entiers. Python est un peu plus large et vous permet d’obtenir le reste d’un nombre à virgule flottante pour le nombre de fois où le nombre peut être divisé en:

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

"La notion mathématique de l'arithmétique modulo fonctionne également pour les valeurs à virgule flottante. C'est l'un des premiers problèmes abordés par Donald Knuth Dans son classique The Art of Computer Programming (volume I) Ie c'était autrefois des connaissances de base. "

L'opérateur de module en virgule flottante est défini comme suit:

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

Comme indiqué, l’opération «non-op» de l’opérateur% sur les nombres en virgule flottante apparaîtêtre lié aux normes. Le CRTL fournit "fmod", et généralement "reste" Ainsi, pour effectuer% sur les nombres fp. La différence entre ces deux mensonges réside dans la manière dont ils gèrent l'arrondi intermédiaire en iquot.

'reste' utilise un arrondi au plus proche et 'fmod' utilise un simple tronqué.

Si vous écrivez vos propres classes numériques C++, rien ne vous empêche De modifier l'héritage no-op, en incluant un opérateur surchargé%.

Meilleures salutations

0
Love