Beefy Boxes and Bandwidth Generously Provided by pair Networks
Problems? Is your data what you think it is?
 
PerlMonks  

Re^3: A locale independent sprintf?

by kcott (Archbishop)
on Jul 29, 2020 at 03:37 UTC ( [id://11119934]=note: print w/replies, xml ) Need Help??


in reply to Re^2: A locale independent sprintf?
in thread A locale independent sprintf?

Using y/,/./, instead of s/,/./, should be faster (see "perlperf: Search and replace or tr"). Obviously, I can't say whether it will be noticeably or usefully faster.

You may want the 'r' modifier. Here's a somewhat fudged example for demonstration purposes:

$ perl -E 'say sprintf("3,%d", 14)' 3,14 $ perl -E 'say sprintf("3,%d", 14) =~ y/,/./' Can't modify constant item in transliteration (tr///) at -e line 1, at + EOF Execution of -e aborted due to compilation errors. $ perl -E 'say sprintf("3,%d", 14) =~ y/,/./r' 3.14

If you try this, I'd be interested in what sort of speed improvement you see.

— Ken

Replies are listed 'Best First'.
Re^4: A locale independent sprintf?
by swl (Parson) on Jul 29, 2020 at 04:06 UTC

    Good point. I'll see if I can set up some benchmarking and post the results.

    Update:

    Running the code below under ubuntu bash under windows with LC_NUMERIC set to de_DE.iso88591 indicates that s///r is about 20% faster than y//r. Both are in the order of millions per second, though.

    And as yet another update, the order does switch between runs so it's not a consistent outcome.

    Results:

    de_DE.iso88591 3,1 3.1 3.1 Rate y_sprintf s_sprintf sprintf y_sprintf 4646523/s -- -19% -63% s_sprintf 5721423/s 23% -- -54% sprintf 12396265/s 167% 117% --

    Code:

    use Benchmark qw {:all}; use 5.016; local $| = 1; use POSIX qw /locale_h/; use locale; print POSIX::setlocale(LC_NUMERIC) . "\n"; my $x; $x = sprintf "%.2g", 3.14; print "$x\n"; $x = sprintf ("%.2g", 3.14) =~ y/,/./r; print "$x\n"; $x = sprintf ("%.2g", 3.14) =~ s/,/./r; print "$x\n"; cmpthese ( -3, { sprintf => 'use strict; use warnings; my $x = sprintf ("%.2g +", 3.14)', y_sprintf => 'use strict; use warnings; my $x = sprintf ("%.2g +", 3.14) =~ y/,/./r', s_sprintf => 'use strict; use warnings; my $x = sprintf ("%.2g +", 3.14) =~ s/,/./r', } );

    (post was further updated to distinguish results from code)

      Interesting and surprising results. You said "the order does switch between runs" but I don't see that in any of the results you posted; there is quite a substantial fluctuation though (11% to 65%).

      I tried with something closer to the code in perlperf to which I linked earlier. I have Cygwin on Win10. I also have Perlbrew. I originally ran under 5.32.0; then switched to 5.30.0 to match your version — there were no significant differences in results. As my locale uses '.', not ',', I simply swapped the substitution (y/./,/ instead of y/,/./). Here's the code I used:

      #!/usr/bin/env perl use 5.016; use warnings; use Benchmark 'cmpthese'; use POSIX 'locale_h'; say POSIX::setlocale(LC_NUMERIC); say sprintf('%.2g', 3.14); say sprintf('%.2g', 3.14) =~ s/\./,/r; say sprintf('%.2g', 3.14) =~ y/./,/r; cmpthese 0 => { sprintf => sub { my $str = sprintf('%.2g', 3.14); return $str; }, y_sprintf => sub { my $str = sprintf('%.2g', 3.14) =~ y/./,/r; ret +urn $str; }, s_sprintf => sub { my $str = sprintf('%.2g', 3.14) =~ s/\./,/r; re +turn $str; }, };

      Here's a typically result:

      $ ./pm_11119934_bench_locale_s_y.pl en_AU.UTF-8 3.1 3,1 3,1 Rate s_sprintf y_sprintf sprintf s_sprintf 2940825/s -- -46% -85% y_sprintf 5493603/s 87% -- -72% sprintf 19713322/s 570% 259% --

      I ran it 5 times with 5.32.0, then 5 times with 5.30.0. The 87% in the representative run only ranged between 85% and 89% in all runs. So, I'm getting y/// almost twice as fast as s///; compared with your s/// being variably faster than y///.

      I added in the 'use strict; use warnings;' which you had. Now the results varied (85% 88% 21% 71% 75%) but 'y_sprintf' was still always faster. (I suspect the 21% is bogus — perhaps some short-lived background process fired up at that time.)

      I then added the 'use locale;' that you had and this substantially slowed down processing: 'y_sprintf' was still faster than 's_sprintf' but I wouldn't say significantly so (5% 1% 7% 12% 8%).

      I next replaced my subs with your strings (',' and '.' swapped as before). Again, 'y_sprintf' was faster and this time closer to, albeit more spread out than, my original results (75% 89% 87% 92% 90%).

      So, I can't replicate your s/// being faster than y///; all my tests indicated that the opposite was the case. I think the addition of 'use strict; use warnings;' was probably unnecessary for the benchmark; and perhaps a distraction. I don't know enough about locales to confidently comment; however, it would seem that if you can live without 'use locale;' that would be a good thing (its doco, locale, has warnings about its use). Perhaps try with some of my variations to see if you get different results.

      — Ken

        I neglected to respond to this point in my other post:

        however, it would seem that if you can live without 'use locale;' that would be a good thing.

        I'm in full agreement here, and don't use it my own code. It's the side effect it being called in another package (Gtk2 in this case) that triggered the issue with my own system.

        salva's recommendation of using no locale in 11119943 and 11119948 looks good to me, and I'll be reaching for it next time I strike this issue.

        The order did switch a little between runs, but that largely ceased once I stopped fiddling about with other processes while the benchmarks were running. I get the same for a locale using a dot as the decimal separator (same WSL system and perl, and also for Strawberry perl 5.28.1). I'll have to try on a native linux machine.

        I'm not sure why your results are so different. The results I showed use a de_DE locale, so perhaps there is overhead when locale handling is triggered. There are also noise effects with benchmarking, although the numbers are pretty distinct in this case. It could also just be my system.

        As for use strict and use warnings, I've been bitten before with string based benchmarking when trying to avoid sub overheads. Taking them out makes no difference to the results (see below, although there is one case where y is faster than s).

        The underlying benchmark code actually calls no strict before it evals code passed as strings. Note the _doeval call in the code generation when a string is passed.

        Results without strict and warnings:

        de_DE.iso88591 3,1 3.1 3.1 Rate y_sprintf s_sprintf sprintf y_sprintf 4515837/s -- -34% -67% s_sprintf 6804054/s 51% -- -50% sprintf 13639660/s 202% 100% -- Rate s_sprintf y_sprintf sprintf s_sprintf 4065578/s -- -14% -64% y_sprintf 4737930/s 17% -- -58% sprintf 11298563/s 178% 138% -- Rate y_sprintf s_sprintf sprintf y_sprintf 4822333/s -- -36% -61% s_sprintf 7501079/s 56% -- -39% sprintf 12255085/s 154% 63% -- Rate y_sprintf s_sprintf sprintf y_sprintf 4712721/s -- -40% -65% s_sprintf 7853825/s 67% -- -42% sprintf 13493133/s 186% 72% -- Rate y_sprintf s_sprintf sprintf y_sprintf 4521907/s -- -33% -66% s_sprintf 6739662/s 49% -- -50% sprintf 13393012/s 196% 99% -- Rate y_sprintf s_sprintf sprintf y_sprintf 4736894/s -- -37% -58% s_sprintf 7546779/s 59% -- -34% sprintf 11352494/s 140% 50% -- Rate y_sprintf s_sprintf sprintf y_sprintf 4954521/s -- -9% -68% s_sprintf 5458237/s 10% -- -64% sprintf 15366383/s 210% 182% -- Rate y_sprintf s_sprintf sprintf y_sprintf 4728476/s -- -33% -65% s_sprintf 7101698/s 50% -- -47% sprintf 13504703/s 186% 90% -- Rate y_sprintf s_sprintf sprintf y_sprintf 4823862/s -- -21% -65% s_sprintf 6083467/s 26% -- -56% sprintf 13732768/s 185% 126% -- Rate y_sprintf s_sprintf sprintf y_sprintf 4290706/s -- -39% -65% s_sprintf 6993552/s 63% -- -42% sprintf 12119185/s 182% 73% --

      Some extra runs while not interacting with the machine. Perl is 5.30.0 via perlbrew under WSL.

      perl -v | head -2 | tail -1 This is perl 5, version 30, subversion 0 (v5.30.0) built for x86_64-li +nux

      Results:

      de_DE.iso88591 3,1 3.1 3.1 Rate y_sprintf s_sprintf sprintf y_sprintf 4716774/s -- -33% -63% s_sprintf 7052758/s 50% -- -45% sprintf 12712918/s 170% 80% -- Rate y_sprintf s_sprintf sprintf y_sprintf 4816895/s -- -34% -61% s_sprintf 7286043/s 51% -- -41% sprintf 12366711/s 157% 70% -- Rate y_sprintf s_sprintf sprintf y_sprintf 4919055/s -- -32% -70% s_sprintf 7182801/s 46% -- -55% sprintf 16134317/s 228% 125% -- Rate y_sprintf s_sprintf sprintf y_sprintf 4694110/s -- -31% -65% s_sprintf 6766241/s 44% -- -50% sprintf 13495072/s 187% 99% -- Rate y_sprintf s_sprintf sprintf y_sprintf 4661016/s -- -36% -70% s_sprintf 7310428/s 57% -- -53% sprintf 15604067/s 235% 113% -- Rate y_sprintf s_sprintf sprintf y_sprintf 5036750/s -- -10% -62% s_sprintf 5583036/s 11% -- -58% sprintf 13364520/s 165% 139% -- Rate y_sprintf s_sprintf sprintf y_sprintf 4737843/s -- -39% -61% s_sprintf 7805896/s 65% -- -36% sprintf 12216419/s 158% 57% -- Rate y_sprintf s_sprintf sprintf y_sprintf 4921710/s -- -31% -62% s_sprintf 7171893/s 46% -- -45% sprintf 12952997/s 163% 81% -- Rate y_sprintf s_sprintf sprintf y_sprintf 5370220/s -- -26% -62% s_sprintf 7269597/s 35% -- -49% sprintf 14253514/s 165% 96% -- Rate y_sprintf s_sprintf sprintf y_sprintf 4708990/s -- -33% -63% s_sprintf 6986810/s 48% -- -45% sprintf 12723873/s 170% 82% --

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: note [id://11119934]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others contemplating the Monastery: (7)
As of 2024-04-16 17:10 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found