Me pregunto si el módulo/recordatorio (%) no funciona correctamente.
As example: a = 4.49 b = 449.0 when I do it b % a, it is not showing 0.0, it is showing 4.489999999999997Quiero saber la causa raíz de este comportamiento.
¿Qué tendrá que obtener 0.0 para 449%4.49?
Permítame darle algunas sugerencias.
Quiero saber la causa raíz de este comportamiento.
Es porque no todos los literales de coma flotante (decimales) se pueden representar exactamente como un número binario de coma flotante.
449.0 se puede representar exactamente como un flotante, pero 4.49 no. Su valor exacto es:
sprintf('%.49f', 4.49) #=> "4.4900000000000002131628207280300557613372802734375" '%.49f' imprime el valor con 49 dígitos fraccionarios que resulta ser la cantidad correcta para este valor. (pura coincidencia)
El valor anterior, que es un poco mayor que 4,49, solo cabe 99 veces en 449. Calculemos el resto:
99 * 4.4900000000000002131628207280300557613372802734375 = 444.5100000000000211031192520749755203723907470703125 449.0 - 444.5100000000000211031192520749755203723907470703125 = 4.4899999999999788968807479250244796276092529296875 Que es (nuevamente exactamente) lo que devuelve 449 % 4.49 :
sprintf('%.49f', 449 % 4.49) #=> "4.4899999999999788968807479250244796276092529296875"La aritmética de coma flotante no se puede representar con precisión en binary , y la clase Float de Ruby lo deja extremadamente claro en la parte superior donde dice:
Un objeto Float representa un número real a veces inexacto utilizando la representación de punto flotante de doble precisión de la arquitectura nativa.
Los flotadores todavía se usan a menudo como "suficientemente buenos" para ciertos casos de uso. Sin embargo, Ruby proporciona bastantes alternativas con varios métodos de inicialización, conversión o coerción cuando necesita representar fracciones, decimales u otros tipos de números con mayor precisión o exactitud:
Aunque personalmente me gusta BigDecimal por su flexibilidad en el manejo de valores flotantes de alta precisión, en la mayoría de los casos, lo más seguro es convertir su valor flotante en un número racional antes de operar con él y luego volver a convertirlo si necesita el resultado en un número diferente. formato que el valor de retorno predeterminado de la expresión. Por ejemplo, para convertir su Flotante en Racional antes de operar en él:
a = 4.49 b = 449.0 b.to_r % a #=> 0.0Tenga en cuenta que generalmente solo necesita convertir/forzar uno de sus dos valores numéricos para que esto funcione, ya que Ruby generalmente reconoce internamente que necesita operar con tipos de datos similares. Por ejemplo, lo mismo ocurre con Floats:
4.0 % 3 #=> 1.0En este caso y en mi plataforma, el resultado es correcto independientemente del hecho de que el segundo ejemplo usa un Flotante y un Entero en la expresión. El punto aquí es que solo uno de los dos números debe ser un Flotante para que Ruby determine que necesita tratarlos a ambos como un Flotante y devolver un Flotante como el valor.
Es posible que haya casos extremos en los que Ruby no convierta automáticamente sus valores correctamente cuando solo convierta uno de ellos explícitamente, pero para la mayoría de los propósitos prácticos, debería poder confiar en él para todos los tipos numéricos básicos y (al menos en mi experiencia ) con BigDecimal.