Recientemente me encontré con un problema que podría resolverse fácilmente usando la división de módulo, pero la entrada era un flotador:
Dada una función periódica (p
sin
. Ej. ) Y una función de computadora que solo puede calcularla dentro del rango del período (p. Ej. [-Π, π]), cree una función que pueda manejar cualquier entrada.
La solución "obvia" es algo como:
#include <cmath>
float sin(float x){
return limited_sin((x + M_PI) % (2 *M_PI) - M_PI);
}
¿Por qué no funciona esto? Me sale este error:
error: invalid operands of types double and double to binary operator %
Curiosamente, funciona en Python:
def sin(x):
return limited_sin((x + math.pi) % (2 * math.pi) - math.pi)
sin(x)
valores grandes de enx
realidad requiere un proceso de reducción de argumentos trascendentales muy difícil que no puede funcionar con ninguna aproximación finita de pi.fmod
es probable que el instructor esté buscando.Respuestas:
Porque la noción matemática normal de "resto" solo es aplicable a la división de enteros. es decir, la división que se requiere para generar un cociente entero.
Para extender el concepto de "resto" a números reales, debe introducir un nuevo tipo de operación "híbrida" que generaría cocientes enteros para operandos reales . El lenguaje Core C no admite dicha operación, pero se proporciona como una
fmod
función de biblioteca estándar , así como tambiénremainder
funciona en C99. (Tenga en cuenta que estas funciones no son las mismas y tienen algunas peculiaridades. En particular, no siguen las reglas de redondeo de la división de enteros).fuente
(a/b)*b
ya es iguala
[en la medida en que se pueda hacer tal declaración para tipos de coma flotante], pora%b
lo que nunca sería particularmente útil.%
operador para punto flotante, supongo, seríaa-(a/b)*b
, que sería 0 o un valor muy pequeño.Estás buscando fmod () .
Supongo que para responder más específicamente a su pregunta, en los lenguajes más antiguos, el
%
operador se definía simplemente como una división modular entera y en los lenguajes más nuevos decidieron ampliar la definición del operador.EDITAR: Si tuviera que apostar a adivinar por qué, diría que es porque la idea de la aritmética modular se origina en la teoría de números y trata específicamente con números enteros.
fuente
Realmente no puedo decirlo con certeza , pero supongo que es principalmente histórico. Muchos de los primeros compiladores de C no admitían el punto flotante en absoluto. Se agregó más tarde, e incluso entonces no tan completamente: se agregó principalmente el tipo de datos y las operaciones más primitivas se admitieron en el lenguaje, pero todo lo demás se dejó a la biblioteca estándar.
fuente
El operador de módulo
%
en C y C ++ está definido para dos enteros, sin embargo, hay unafmod()
función disponible para su uso con dobles.fuente
sin(fmod(x,3.14))
o inclusosin(fmod(x,M_PI))
no es igual asin(x)
valores grandes dex
. De hecho, los valores pueden diferir hasta en 2,0.%
el operador restante y no un operador de módulo?Las limitaciones están en los estándares:
C11 (ISO / IEC 9899: 201x) §6.5.5 Operadores multiplicativos
C ++ 11 (ISO / IEC 14882: 2011) §5.6 Operadores multiplicativos
La solución es usar
fmod
, que es exactamente la razón por la que los operandos de%
están limitados al tipo entero en primer lugar, de acuerdo con C99 Justificación §6.5.5 Operadores multiplicativos :fuente
tratar
fmod
fuente
El operador% le da un REMAINDER (otro nombre para módulo) de un número. Para C / C ++, esto solo se define para operaciones con números enteros. Python es un poco más amplio y le permite obtener el resto de un número de punto flotante para el resto de cuántas veces el número se puede dividir en él:
>>> 4 % math.pi 0.85840734641020688 >>> 4 - math.pi 0.85840734641020688 >>>
fuente
:P
El
%
operador no funciona en C ++, cuando intenta encontrar el resto de dos números que son del tipoFloat
oDouble
.Por lo tanto, podría intentar usar la
fmod
función demath.h
/cmath.h
o podría usar estas líneas de código para evitar usar ese archivo de encabezado: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 ));
}
fuente
"La noción matemática de módulo aritmético también funciona para valores de coma flotante, y este es uno de los primeros temas que Donald Knuth discute en su clásico El arte de la programación informática (volumen I). Es decir, alguna vez fue conocimiento básico".
El operador de módulo de coma flotante se define de la siguiente manera:
m = num - iquot*den ; where iquot = int( num/den )
Como se indicó, la no operación del operador% en números de punto flotante parece estar relacionada con los estándares. El CRTL proporciona 'fmod', y generalmente también 'resto', para realizar% en números fp. La diferencia entre estos dos radica en cómo manejan el redondeo intermedio 'iquot'.
'resto' usa redondeo al más cercano y 'fmod' usa truncar simple.
Si escribe sus propias clases numéricas de C ++, nada le impide modificar el legado de no-op, al incluir un operador sobrecargado%.
Atentamente
fuente