Pergunta

Em uma plataforma de 32 bits do Windows eu tenho que ler alguns números que, este foi inesperado, pode ter valores tão grandes quanto 99999999999, mas não mais. Tentando sprintf("%011d", $myNum)-los gera um overflow: -2147483648.

Eu não posso usar o módulo BigInt porque neste caso devo profundamente alterar o código. Eu não posso controlar o formato como corda, sprintf("%011s", $numero), porque o sinal negativo é tratado incorretamente.

Como posso gerenciar isso? Poderia embalar / descompactar ser de alguma ajuda?

Foi útil?

Solução

Tente formatá-lo como um flutuador com nenhuma parte fração:

$ perl -v
This is perl, v5.6.1 built for sun4-solaris
...

$ perl -e 'printf "%011d\n", 99999999999'
-0000000001

$ perl -e 'printf "%011.0f\n", 99999999999'
99999999999

Outras dicas

Sim, um dos pontos cegos numéricos do Perl é formatação; Perl trata automaticamente representar números como inteiros ou flutua muito bem, mas então coage-los em um ou outro quando os formatos printf numéricos são utilizados, mesmo quando isso não é apropriada. E printf realmente não lidar com valores BIGINT em tudo (exceto tratando -los como cordas e converter isso para um número, com a perda de precisão).

Usando% s em vez de% d com qualquer número que você não está certo de que será de forma adequada intervalo é uma boa solução, exceto quando você nota para números negativos. Lidar aqueles, você vai ter que escrever algum código Perl.

Não sou especialista Perl, e talvez eu estou faltando algum tipo de manipulação automática de bignums aqui, mas não é isso simplesmente um caso de estouro de inteiro? Um inteiro de 32 bits não pode segurar números que são tão grandes quanto 99999999999.

De qualquer forma, eu obter o mesmo resultado com Perl v5.8.8 na minha máquina Linux de 32 bits, e parece que printf com "% d" não lidar com números maiores.

Eu acho que a sua cópia do Perl deve ser quebrado, este é da versão de CygWin (5.10):

pax$ perl -e 'printf("%011d\n", 99999999999);'
99999999999

pax$ perl -v

This is perl, v5.10.0 built for cygwin-thread-multi-64int
(with 6 registered patches, see perl -V for more detail)

Copyright 1987-2007, Larry Wall

Perl may be copied only under the terms of either the Artistic License or the
GNU General Public License, which may be found in the Perl 5 source kit.

Complete documentation for Perl, including FAQ lists, should be found on
this system using "man perl" or "perldoc perl".  If you have access to the
Internet, point your browser at http://www.perl.org/, the Perl Home Page.

Qual versão você está correndo (saída de perl -v)?

Você pode ter que obter uma versão habilitada de 64 bits do Perl [e, possivelmente, uma nova máquina de produção de 64 bits] (note a "cygwin-thread-multi-64int" na minha saída). Que, pelo menos evitar a necessidade de alterar o código.

Eu estou dizendo isso com base no que você não quer alterar o código muito (ou seja, você tem medo quebrando as coisas). A solução de hardware novo, enquanto um pouco caro, quase certamente não vai exigir que você altere o software em tudo . Tudo depende das suas prioridades.

Outra possibilidade é que o próprio Perl pode estar armazenando o número corretamente, mas apenas exibi-lo devido errada a uma fraqueza printf(). Nesse caso, você pode querer tentar:

$million = 1000000;
$bignum = 99999999999;
$firstbit = int($bignum / $million);
$secondbit = $bignum - $firstbit * million;
printf ("%d%06d\n",$firstbit,$secondbit);

Coloque isso em uma função e chamar a função para retornar uma string, como:

sub big_honkin_number($) {
    $million = 1_000_000;
    $bignum = shift;
    $firstbit = int($bignum / $million);
    $secondbit = $bignum - $firstbit * $million;
    return sprintf("%d%06d\n", $firstbit, $secondbit);
}
printf ("%s", big_honkin_number (99_999_999_999));

Note que eu testei este, mas na plataforma de 64 bits -. Você precisa fazer seu próprio teste de 32 bits, mas você pode usar qualquer fator de escala que você quer (incluindo mais de dois segmentos se necessário)

Update: Esse truque big_honkin_number() funciona bem em um 32-bit Perl por isso parece que é apenas as funções printf() que estão enchendo-lo:

pax@pax-desktop:~$ perl -v

This is perl, v5.8.8 built for i486-linux-gnu-thread-multi

Copyright 1987-2006, Larry Wall

Perl may be copied only under the terms of either the Artistic License or the
GNU General Public License, which may be found in the Perl 5 source kit.

Complete documentation for Perl, including FAQ lists, should be found on
this system using "man perl" or "perldoc perl".  If you have access to the
Internet, point your browser at http://www.perl.org/, the Perl Home Page.

pax@pax-desktop:~$ perl qq.pl
99999999999
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top