The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.

NOMBRE

perlnumber - Semántica de números y operaciones numéricas en Perl

SINOPSIS

    $n = 1234;              # entero decimal
    $n = 0b1110011;         # entero binario
    $n = 01234;             # entero octal
    $n = 0x1234;            # entero hexadecimal
    $n = 12.34e-56;         # notación exponencial
    $n = "-12.34e56";       # número especificado como una cadena
    $n = "1234";            # número especificado como una cadena

DESCRIPCIÓN

En este documento se describe el procesamiento interno de valores numéricos en Perl.

Se omite completamente la funcionalidad de sobrecarga de operadores de Perl, que permite establecer comportamientos definidos por el usuario para números, como operaciones con enteros arbitrariamente grandes, números de punto flotante de precisión arbitraria, operaciones con números "exóticos" (como la aritmética modular o la aritmética de números p-ádicos), etc. Encontrará información detallada en overload.

Cómo se almacenan los números

Perl puede representar los números internamente de 3 maneras distintas: como enteros nativos, como números de punto flotante nativos y como cadenas decimales. Las cadenas decimales pueden tener una parte en notación exponencial (por ejemplo, "12.34e-56"). Aquí nativo significa "formato admitido por el compilador de C que se usó para compilar perl".

En el caso de los enteros nativos, el término "nativo" no tiene las mismas implicaciones que para los números de punto flotante nativos. La única implicación del término "nativo" para los enteros es que los límites máximo y mínimo de las cantidades verdaderamente enteras admitidas son cercanos a potencias de 2. En cambio, existe una restricción intrínseca para los números de punto flotante "nativos": solo se pueden representar los números que tengan una representación relativamente "corta" al convertirse en una fracción binaria. Por ejemplo, 0.9 no se puede representar como un número de punto flotante nativo porque la fracción binaria correspondiente a 0.9 es infinita:

  binary0.1110011001100...

donde la secuencia 1100 se repite una y otra vez. Además de esta limitación, el exponente del número binario también está restringido cuando se representa como un número de punto flotante. En el hardware típico, los valores de punto flotante pueden almacenar números que tengan hasta 53 dígitos binarios, y con exponentes binarios entre -1024 y 1024. En representación decimal, estos límites se acercan a 16 dígitos decimales y exponentes decimales en el intervalo -304..304. Como consecuencia, Perl no puede almacenar un número como 12345678901234567 en forma de número de punto flotante para estas arquitecturas sin pérdida de información.

De manera similar, las cadenas decimales solo pueden representar números que tengan una expansión decimal finita. Al ser cadenas y, por tanto, al tener una longitud arbitraria, no existe un límite práctico para el exponente o el número de dígitos decimales para estos números. (Pero no olvide que lo que estamos describiendo son solo las normas del almacenamiento de estos números. El hecho de poder almacenar números tan "grandes" no significa que en las operaciones con estos números se usen todos los dígitos significativos. Encontrará información detallada en "Operadores numéricos y conversiones numéricas").

De hecho, los números almacenados en formato de entero nativo se pueden almacenar en forma nativa con signo o sin signo. Así, los límites para números Perl almacenados como enteros nativos serán normalmente -2**31..2**32-1, con las modificaciones correspondientes en el caso de los enteros de 64 bits. Insistimos: esto no significa que Perl sólo puede realizar operaciones con enteros de este intervalo; es posible almacenar muchos más enteros en formato de punto flotante.

En resumen, en Perl los valores numéricos solo pueden almacenar números que tengan una expansión decimal finita o una expansión binaria "corta".

Operadores numéricos y conversiones numéricas

Como se mencionó antes, Perl puede almacenar un número en uno de tres formatos distintos, pero la mayoría de los operadores suelen admitir solo uno de esos formatos. Cuando se pasa un valor numérico como argumento a un operador así, se convierte a un formato comprensible para el operador.

Hay seis conversiones posibles:

  entero nativo         --> punto flotante nativo (*)
  entero nativo         --> cadena decimal
  punto flotante nativo --> entero nativo (*)
  punto flotante nativo --> cadena decimal (*)
  cadena decimal        --> entero nativo
  cadena decimal        --> punto flotante nativo (*)

Estas conversiones obedecen las siguientes normas generales:

  • Si el número de origen se puede representar en la forma de destino, se usa esa representación.

  • Si el número de origen está fuera de los límites representables en la forma de destino, se usa una representación del límite más cercano. (Pérdida de información)

  • Si el número de origen está entre dos números representables en la forma de destino, se usa una representación de uno de estos números. (Pérdida de información)

  • En las conversiones punto flotante nativo --> entero nativo, la magnitud del resultado es menor o igual que la magnitud del número de origen. ("Redondeo a cero")

  • Si no se puede aplicar la conversión cadena decimal --> entero nativo sin pérdida de información, el resultado es compatible con la secuencia de conversiones cadena decimal --> punto flotante nativo --> entero nativo. En particular, hay un sesgo muy fuerte de redondeo a 0, aunque es posible que un número como "0.99999999999999999999" se redondee a 1.

RESTRICCIÓN: las conversiones anteriores marcadas con (*) implican pasos ejecutados por el compilador de C. En particular, determinados errores o características del compilador usado pueden provocar la infracción de algunas de las normas anteriores.

Tipos de operaciones numéricas en Perl

En Perl, las operaciones que consumen un argumento numérico tratan al argumento de una de cuatro maneras posibles: pueden forzar la conversión a uno de los formatos de entero/número de punto flotante/cadena, o pueden comportarse de una manera diferente en función del formato del operando. Forzar la conversión de un valor numérico a un formato específico no cambia el número almacenado en el valor.

Todos los operadores que necesitan un argumento con formato de entero tratan al argumento como en la aritmética modular (p. ej., mod 2**32 en una arquitectura de 32 bits). Así, sprintf "%u", -1 produce el mismo resultado que sprintf "%u", ~0.

Operadores aritméticos

Los operadores binarios + - * / % == != > < >= y <=, y los operadores unarios abs y --, intentan convertir los argumentos en enteros. Si ambas conversiones son posibles sin pérdida de precisión y se puede realizar la operación sin pérdida de precisión, se usa el resultado entero. De lo contrario, los argumentos se convierten al formato de punto flotante y se usa el resultado de punto flotante. El almacenamiento en caché de las conversiones descritas arriba significa que la conversión a enteros no desecha las partes fraccionarias en los números de punto flotante.

++

++ se comporta como los operadores anteriores, con la diferencia de que si se aplica a una cadena que tenga el formato /^[a-zA-Z]*[0-9]*\z/, se usa el incremento de cadena descrito en perlop.

Operadores aritméticos con use integer activo

En ámbitos en los que use integer; está activo, casi todos los operadores indicados arriba forzarán la conversión de sus argumentos a formato de entero, y devolverán un resultado entero. Las excepciones son abs, ++ y --, que no cambian su comportamiento con use integer;

Otros operadores matemáticos

Algunos operadores, como **, sin y exp, fuerzan la conversión de los argumentos al formato de punto flotante.

Operadores bit a bit

Fuerzan la conversión de los argumentos al formato de entero si no son cadenas.

Operadores bit a bit con use integer activo

Fuerzan la conversión de los argumentos al formato de entero. Además, las operaciones de desplazamiento usan internamente enteros con signo en lugar de los enteros sin signo predeterminados.

Operadores que consumen un entero

Fuerzan la conversión del argumento al formato de entero. Esto es aplicable, por ejemplo, a los argumentos tercero y cuarto de sysread.

Operadores que consumen una cadena

Fuerzan la conversión del argumento al formato de cadena. Por ejemplo, esto es aplicable a printf "%s", $valor.

Aunque forzar la conversión de un argumento a un formato específico no cambia el número almacenado, Perl recuerda el resultado de las conversiones. Así, aunque la primera conversión tarde un poco más, al repetir una operación no será necesario repetir la conversión.

AUTOR

Ilya Zakharevich ilya@math.ohio-state.edu

Ajustes editoriales de Gurusamy Sarathy <gsar@ActiveState.com>

Actualizaciones para 5.8.0 de Nicholas Clark <nick@ccl4.org>

VEA TAMBIÉN

overload, perlop

TRADUCTORES

  • Joaquín Ferrero (Tech Lead)

  • Enrique Nell (Language Lead)