Strange behavior when printing a 4G+ integer on 32bits platform.

2018-11-17 Thread Tetsuo Handa
Hello.

I want to represent up to a few hundreds gigabytes for file size.

On 32bits platform, I noticed that

  my $value = ...;
  printf("%u\n", $value);

prints 4294967295 if $value >= 4294967295 whereas

  my $value = ...;
  printf("%s\n", $value);

and

  use Math::BigInt;
  my $value = ...;
  printf("%s\n", Math::BigInt->new($value)->bstr());

print correct value even when $value >= 4294967295.

Is it guaranteed (e.g. described as language specification) that
printf("%s\n", $value) will print correct value for any environment?

-- 
To unsubscribe, e-mail: beginners-unsubscr...@perl.org
For additional commands, e-mail: beginners-h...@perl.org
http://learn.perl.org/




Strange behavior when printing a 4G+ integer on 32bits platform.

2018-11-17 Thread Tetsuo Handa
Hello.

I want to represent up to a few hundreds gigabytes for file size.

On 32bits platform, I noticed that

  my $value = ...;
  printf("%u\n", $value);

prints 4294967295 if $value >= 4294967295 whereas

  my $value = ...;
  printf("%s\n", $value);

and

  use Math::BigInt;
  my $value = ...;
  printf("%s\n", Math::BigInt->new($value)->bstr());

print correct value even when $value >= 4294967295.

Is it guaranteed (e.g. described as language specification) that
printf("%s\n", $value) will print correct value for any environment?

-- 
To unsubscribe, e-mail: beginners-unsubscr...@perl.org
For additional commands, e-mail: beginners-h...@perl.org
http://learn.perl.org/




Re: Strange behavior when printing a 4G+ integer on 32bits platform.

2018-11-15 Thread Tetsuo Handa
On 2018/11/15 9:27, sisyphus wrote:
> Are you actually encountering files larger than 1e15 bytes ?

On 32bit kernels, filesystems would not allow such large files.
For example, max size for xfs filesystem is 16TB.

Even on 64bit userspace, nobody will want to upload such large file
via network.

> If not, then either:
> 
> printf("%s\n", $sb->size);
>   or
> printf("%.15e\n", $sb->size;
>   or
> print $sb->size;
> 
> should be fine.

I see. Thank you.

-- 
To unsubscribe, e-mail: beginners-unsubscr...@perl.org
For additional commands, e-mail: beginners-h...@perl.org
http://learn.perl.org/




Re: Strange behavior when printing a 4G+ integer on 32bits platform.

2018-11-15 Thread Tetsuo Handa
I received a comment from Peter John Acklam (current bigint maintainer).

 Forwarded Message 
Date: Wed, 14 Nov 2018 20:08:27 +0100

Hello

This has actually nothing to do with Math::BigInt. The issue here is that
the conversion "u", converts a number to an unsigned integer before the
integer is printed as a string. On 32 bit systems, an unsigned integer has
values between 0 and 2^32-1, inclusive. On 64 bit systems, the values are
between 0 and 2^64-1. Using input values outside of this range is not a
good idea. It seems that if the input is larger than the maximum value, it
is truncated to the maximum value, but I wouldn't rely on this. On my 64
bit system, the input value is truncated:

$ perl -we 'printf "%u\n", "1e30"'
18446744073709551615

On the other hand, when the input value is smaller than zero, the input is
not truncated to zero on my system:

$ perl -we 'printf "%u\n", "-1e30"'
9223372036854775808

As for the "s" conversion, it never converts the input to an integer (or
float). Strings are passed right through, unmodified. So that's why I get

$ perl -we 'printf "%s\n", "1e30"'
1e30

If you want "1e30" to be displayed as "100...", Math::BigInt is handy for
converting "1e30" to "100...":

$ perl -MMath::BigInt -we 'printf "%s\n", Math::BigInt->new("1e30")->bstr()'
100

Regarding the question "Is it guaranteed (e.g. described as language
specification) that printf("%s\n", $value) will print correct value
for any environment?"
Yes, the "s" conversion passes strings through unmodified.

If you have more questions or want more clarification, don't hesitate to
ask again.

Best regards,
Peter

On 2018/11/13 23:57, Mike Flannigan wrote:
> 
> I don't have an answer for you, but I find this
> interesting.  I note the same issue in 64bit
> up near
> 18446744073709551615
> 
> I'm guessing the guy who wrote
> Math::BigInt
> may have the answer.
> 
> 
> Mike
> 
> 
> On 11/13/2018 8:07 AM, Tetsuo Handa wrote:
>> Hello.
>>
>> I want to represent up to a few hundreds gigabytes for file size.
>>
>> On 32bits platform, I noticed that
>>
>>    my $value = ...;
>>    printf("%u\n", $value);
>>
>> prints 4294967295 if $value >= 4294967295 whereas
>>
>>    my $value = ...;
>>    printf("%s\n", $value);
>>
>> and
>>
>>    use Math::BigInt;
>>    my $value = ...;
>>    printf("%s\n", Math::BigInt->new($value)->bstr());
>>
>> print correct value even when $value >= 4294967295.
>>
>> Is it guaranteed (e.g. described as language specification) that
>> printf("%s\n", $value) will print correct value for any environment?
>>
> 

-- 
To unsubscribe, e-mail: beginners-unsubscr...@perl.org
For additional commands, e-mail: beginners-h...@perl.org
http://learn.perl.org/




Re: Strange behavior when printing a 4G+ integer on 32bits platform.

2018-11-14 Thread sisyphus
On Thu, Nov 15, 2018 at 1:49 AM Tetsuo Handa <
penguin-ker...@i-love.sakura.ne.jp> wrote:

> 32bits userspace on 64bits kernel:
> # truncate -s 9223372036854775807 test
> # perl -e 'use File::stat; my $sb = lstat("test"); printf("%s\n",
$sb->size);'
> 9.22337203685478e+18
> # perl -e 'use File::stat; my $sb = lstat("test"); printf("%u\n",
$sb->size);'
> 4294967295

Note that "%s" is providing an inaccurate (rounded) result.
Doing :

"%s\n", $sb->size

will provide correct results if the file size is less than or equal
to 1e+15 bytes but, for larger sizes, the value that is output is subject
to rounding.

Doing :

 "%.15e\n", $sb->size

provides an improvement on "%s" in that, for files up to
9.007199254740992e+015 bytes, it will provide a correct figure:

If you're encountering files larger than 9.007199254740992e+015 bytes, the
best solution is to simply build perl with -Duse64bitint, though building
with -Duselongdouble would probably also address this issue by providing a
64-bit precision NV.
I do, of course, understand that such solutions might be inapplicable
regarding your situation.

Are you actually encountering files larger than 1e15 bytes ?
If not, then either:

printf("%s\n", $sb->size);
  or
printf("%.15e\n", $sb->size;
  or
print $sb->size;

should be fine.


Cheers,
Rob


Re: Strange behavior when printing a 4G+ integer on 32bits platform.

2018-11-14 Thread Tetsuo Handa
On 2018/11/14 21:46, sisyphus wrote:
> On Wed, Nov 14, 2018 at 10:20 PM Tetsuo Handa 
>  wrote:
> 
>> Even on 32bit environments (at least for Linux), lstat() calls 64bit version
> 

Here is some test results on Linux.

32bits userspace on 32bits kernel:
# truncate -s 17592186044415 test
# perl -e 'use File::stat; my $sb = lstat("test"); printf("%s\n", $sb->size);'
17592186044415
# perl -e 'use File::stat; my $sb = lstat("test"); printf("%u\n", $sb->size);'
4294967295

32bits userspace on 64bits kernel:
# truncate -s 9223372036854775807 test
# perl -e 'use File::stat; my $sb = lstat("test"); printf("%s\n", $sb->size);'
9.22337203685478e+18
# perl -e 'use File::stat; my $sb = lstat("test"); printf("%u\n", $sb->size);'
4294967295

64bits userspace on 64bits kernel:
# truncate -s 9223372036854775807 test
# perl -e 'use File::stat; my $sb = lstat("test"); printf("%s\n", $sb->size);'
9223372036854775807
# perl -e 'use File::stat; my $sb = lstat("test"); printf("%u\n", $sb->size);'
9223372036854775807

> When I check on Windows, I find that the value is actually an NV (not an IV
> as I had expected).
> I expect it's the same for you, in which case it's a 53-bit double
> (unless $Config{nvsize} reports a value greater than 8).
> 
> You can test for this using Devel::Peek:
> 

64bits userspace on 64bits kernel:
NV is 8 bytes
SV = IV(0x1f98730) at 0x1f98740
  REFCNT = 1
  FLAGS = (IOK,pIOK)
  IV = 9223372036854775807

32bits userspace on 64bits kernel:
NV is 8 bytes
SV = NV(0x95d7608) at 0x95b45b8
  REFCNT = 1
  FLAGS = (NOK,pNOK)
  NV = 9.22337203685478e+18

Since accurate file size value is lost as soon as it is stored into $sb, doing

  my $x = $sb->size;
  $value = Math::BigInt->new("$x");

won't help. I will use "%s" without Math::BigInt.

-- 
To unsubscribe, e-mail: beginners-unsubscr...@perl.org
For additional commands, e-mail: beginners-h...@perl.org
http://learn.perl.org/




Re: Strange behavior when printing a 4G+ integer on 32bits platform.

2018-11-14 Thread sisyphus
On Wed, Nov 14, 2018 at 10:20 PM Tetsuo Handa <
penguin-ker...@i-love.sakura.ne.jp> wrote:

> Even on 32bit environments (at least for Linux), lstat() calls 64bit
version

When I check on Windows, I find that the value is actually an NV (not an IV
as I had expected).
I expect it's the same for you, in which case it's a 53-bit double
(unless $Config{nvsize} reports a value greater than 8).

You can test for this using Devel::Peek:

use strict;
use warnings;
use Config;
use Devel::Peek;
die "Usage 'perl try.pl filename'"
  unless $ARGV[0];
print "NV is ", $Config{nvsize}, " bytes\n";
my @s = lstat($ARGV[0]);
Dump $s[7];
print "\n\n\n";
Dump $s[8];

__END__

Outputs:
NV is 8 bytes
SV = NV(0x1dbaccc) at 0x1d8e95c
  REFCNT = 1
  FLAGS = (NOK,pNOK)
  NV = 7948



SV = IV(0x1d8e9a8) at 0x1d8e9ac
  REFCNT = 1
  FLAGS = (IOK,pIOK)
  IV = 1481534816

Cheers,
Rob


Re: Strange behavior when printing a 4G+ integer on 32bits platform.

2018-11-14 Thread Tetsuo Handa
On 2018/11/14 19:59, sisyphus wrote:
> On Wed, Nov 14, 2018 at 9:08 PM Tetsuo Handa 
>  wrote
> 
>>  how can I pass $sb->size to Math::BigInt->new() as a string (assuming that 
>> $sb->size is an integer) ?
> 
> To answer the question, you can do:
> 
> my $x = $sb->size;
> $value = Math::BigInt->new("$x");

Wow! I didn't notice that quoting a variable makes a string...

> 
> But doing so is likely to be completely pointless.
> I'm thinking that the real problem is "How, on a 32-bit integer build of
> perl, does one get lstat() to return a correct value for 'size' when the
> size of the file is greater than 4294967295 bytes ?"

Even on 32bit environments (at least for Linux), lstat() calls 64bit version,
and thus capable of storing $sb->size > 4GB. Thus, I think it is no problem.

  strace perl -e 'use File::stat; my $sb = 
lstat("CentOS-5.11-x86_64-bin-DVD-1of2.iso"); print $sb->size;'
  lstat64("CentOS-5.11-x86_64-bin-DVD-1of2.iso", {st_mode=S_IFREG|0644, 
st_size=4674615296, ...}) = 0
  write(1, "4674615296", 10)  = 10

Thank you.

-- 
To unsubscribe, e-mail: beginners-unsubscr...@perl.org
For additional commands, e-mail: beginners-h...@perl.org
http://learn.perl.org/




Re: Strange behavior when printing a 4G+ integer on 32bits platform.

2018-11-14 Thread sisyphus
On Wed, Nov 14, 2018 at 9:08 PM Tetsuo Handa <
penguin-ker...@i-love.sakura.ne.jp> wrote

>  how can I pass $sb->size to Math::BigInt->new() as a string (assuming
that $sb->size is an integer) ?

To answer the question, you can do:

my $x = $sb->size;
$value = Math::BigInt->new("$x");

But doing so is likely to be completely pointless.
I'm thinking that the real problem is "How, on a 32-bit integer build of
perl, does one get lstat() to return a correct value for 'size' when the
size of the file is greater than 4294967295 bytes ?"

I don't perform such exercises with perl, but I'm thinking that the answer
to that question is "This cannot be done".
Assuming that's correct, the simplest solution in my opinion is to build
your perl with 64-bit integer support - which is something that can be done
even with 32-bit compilers.

Given that the OS knows the actual size of the file, another option would
be to have perl query the OS, rather than calling lstat or stat. (I don't
know the details of how to do that - it would depend to at least some
extent on which OS you're running.)

Cheers,
Rob


Re: Strange behavior when printing a 4G+ integer on 32bits platform.

2018-11-14 Thread Tetsuo Handa
Hello, sisyphus.

Thank you for your answer.

> That can fail if $value is so big that it requires more than 15 decimal
> digits to express it accurately.

I want to use like

  (...snipped...)
  my $sb = lstat($file) || next;
  next unless (S_ISREG($sb->mode) && $sb->size);
  (...snipped...)
  $curl->setopt(CURLOPT_URL, sprintf('%s/size=%s/stamp=%s/%s', $cgi_path, 
$sb->size, $stamp, $filename));
  (...snipped...)

and therefore 15 decimal digits will be enough. Who wants to upload 10TB+ file? 
;-)

But for the record who wants to use such large value,

> Note that even with Math::BigInt it's important that you assign the value
> as a string:
> 
> C:\_32>perl -MMath::BigInt -le "printf '%s',
> Math::BigInt->new('901234567890123456789');"
> 901234567890123456789
> 
> If you assign it as number (unquoted):
> 
> C:\_32>perl -MMath::BigInt -le "printf '%s',
> Math::BigInt->new(901234567890123456789);"
> 90123456789012300

how can I pass $sb->size to Math::BigInt->new() as a string (assuming that 
$sb->size is an integer) ?

-- 
To unsubscribe, e-mail: beginners-unsubscr...@perl.org
For additional commands, e-mail: beginners-h...@perl.org
http://learn.perl.org/




Re: Strange behavior when printing a 4G+ integer on 32bits platform.

2018-11-13 Thread sisyphus
On 11/13/2018 8:07 AM, Tetsuo Handa wrote:
> Hello.
>
> I want to represent up to a few hundreds gigabytes for file size.
>
> On 32bits platform, I noticed that
>
>my $value = ...;
>printf("%u\n", $value);
>
> prints 4294967295 if $value >= 4294967295 whereas
>
>my $value = ...;
>printf("%s\n", $value);
>

That can fail if $value is so big that it requires more than 15 decimal
digits to express it accurately.
For example:

C:\_32>perl -le "printf '%s', 901234567890123456789;"
9.01234567890123e+020

As you can see, it's printing the value as 90123456789012300

> and
>
>use Math::BigInt;
>my $value = ...;
>printf("%s\n", Math::BigInt->new($value)->bstr());
>
> print correct value even when $value >= 4294967295.
>
> Is it guaranteed (e.g. described as language specification) that
> printf("%s\n", $value) will print correct value for any environment?
>

If you're dealing with integer values that overflow perl's integer type
(IV), then you're generally better off using a module that accommodates
larger integers.

Math::BigInt is fine for this, though it can be rather slow if you're doing
lots of large calculations.
Other options include Math::Int64 (64-bit integer support),
Math::Int128(128-bit integer support), Math::GMP(multiple precision) and
Math::GMPz (multiple precision).

Note that even with Math::BigInt it's important that you assign the value
as a string:

C:\_32>perl -MMath::BigInt -le "printf '%s',
Math::BigInt->new('901234567890123456789');"
901234567890123456789

If you assign it as number (unquoted):

C:\_32>perl -MMath::BigInt -le "printf '%s',
Math::BigInt->new(901234567890123456789);"
90123456789012300

Similarly, assign as a string when using the other alternative modules
that I mentioned.

Note also that you can just print() the value:

C:\_32>perl -MMath::BigInt -le "print
Math::BigInt->new('901234567890123456789');"
901234567890123456789

There's no need to invoke printf(), and no need to call the bstr() method.

Cheers,
Rob

-- 
To unsubscribe, e-mail: beginners-unsubscr...@perl.org
For additional commands, e-mail: beginners-h...@perl.org
http://learn.perl.org/


Re: Strange behavior when printing a 4G+ integer on 32bits platform.

2018-11-13 Thread Mike Flannigan



I don't have an answer for you, but I find this
interesting.  I note the same issue in 64bit
up near
18446744073709551615

I'm guessing the guy who wrote
Math::BigInt
may have the answer.


Mike


On 11/13/2018 8:07 AM, Tetsuo Handa wrote:

Hello.

I want to represent up to a few hundreds gigabytes for file size.

On 32bits platform, I noticed that

   my $value = ...;
   printf("%u\n", $value);

prints 4294967295 if $value >= 4294967295 whereas

   my $value = ...;
   printf("%s\n", $value);

and

   use Math::BigInt;
   my $value = ...;
   printf("%s\n", Math::BigInt->new($value)->bstr());

print correct value even when $value >= 4294967295.

Is it guaranteed (e.g. described as language specification) that
printf("%s\n", $value) will print correct value for any environment?



--
To unsubscribe, e-mail: beginners-unsubscr...@perl.org
For additional commands, e-mail: beginners-h...@perl.org
http://learn.perl.org/




Strange behavior when printing a 4G+ integer on 32bits platform.

2018-11-13 Thread Tetsuo Handa
Hello.

I want to represent up to a few hundreds gigabytes for file size.

On 32bits platform, I noticed that

  my $value = ...;
  printf("%u\n", $value);

prints 4294967295 if $value >= 4294967295 whereas

  my $value = ...;
  printf("%s\n", $value);

and

  use Math::BigInt;
  my $value = ...;
  printf("%s\n", Math::BigInt->new($value)->bstr());

print correct value even when $value >= 4294967295.

Is it guaranteed (e.g. described as language specification) that
printf("%s\n", $value) will print correct value for any environment?

-- 
To unsubscribe, e-mail: beginners-unsubscr...@perl.org
For additional commands, e-mail: beginners-h...@perl.org
http://learn.perl.org/