chr(0) is just a byte with all 8 bits set to 0. It's considered the NUL byte in many languages because it's useful to do so.
Tossing in bytes::chr() slowed your version down even more. :-(
Update: Corrected per ikegami's response.
My criteria for good software:
- Does it work?
- Can someone else come in, make a change, and be reasonably certain no bugs were introduced?
| [reply] |
NULL is a special pointer in C, and an exceptional value in in SQL and VB.
NUL is ASCII character 0.
I believe you are refereing to NUL.
| [reply] [d/l] [select] |
More to the point, since we've been working with byte values instead of characters for some time now (the very purpose of use bytes), isn't chr(0) indeed the same as '\0'? NUL is a null (notice the lowercase -- just meaning 0-valued and not anything special in jargon terms -- this is Webster's definition 4b or definition 6) byte. chr(0) is a zero-valued byte. NUL is chr(0). Right?UpdateI was thinking for some reason the last couple of days that single-character escapes worked in single quotes, and that only variable interpolation didn't. I don't know why, because I know better than that. I'll blame extreme tiredness, as that's likely the cause.
I'm not an optimization guru or anything, but isn't working with the data at a lower level a common optimization technique? IIRC, it's a big part of why the core C language uses chars that are basically small integers, and that strings are represented by arrays of chars. It's easy for the compiler, and it's very efficient. It's certainly not because it makes programming string-heavy projects easier.
I would really like to see the benchmark run that is showing my code failing the "same output" test, if such data exists. Update: This concerns me about the test, then, because my broken version doesn't seem to have ever killed the test.
| [reply] |
In response to your updated node:
Look at an ASCII chart (2, 3, 4). What's at position 0? It's a byte with all zeros, and yes it's called NUL. It's also referred to as a 'null byte' (all lowercase, four letters). While it's true a null/zero byte can represent something other than NUL, NUL is always represented as a null/zero byte (at least in ASCII and EBCDIC).
When dealing with eight-bit bytes, it shouldn't matter if you have an ASCII character, '\0', 0, "\x00", or "\0". vec(), ikegami's tr/\x00/\xFF/, and anything using use bytes; is working at the byte (or bit, in the case of vec()) level, and not necessarily working on "character" data. Update: it should matter if you have '\0'. It shouldn't matter about the rest. The test isn't failing, though.
I don't need your beer. I'm just trying to help. You can do whatever you like, but I'm not sure where you're getting the idea that '\0' is producing a different end product in these cases. Try "\000" or "\x00" instead, and see if it changes anything at all. I'm guessing using chr(0) is changing absolutely nothing but the speed. Update: and I based this on the results of the Test::More tests that said it was all producing the same output. Apparently, either it's working by some fluke, or the tests are broken.
Take a look at this:
Rate split1 mrm_7 mrm_8 mrm_6
split1 1.08/s -- -100% -100% -100%
mrm_7 1906/s 176180% -- -0% -44%
mrm_8 1910/s 176481% 0% -- -44%
mrm_6 3381/s 312486% 77% 77% --
1..4
ok 1 - split1 gets some value
ok 2 - mrm_7 gets same value
ok 3 - mrm_8 gets same value
ok 4 - mrm_6 gets same value
and here's the code:
#!/usr/bin/perl
use 5.6.0;
use strict;
use warnings FATAL => 'all';
use Benchmark qw( cmpthese );
my $s1 = do_rand(0, 100_000);
my $s2 = do_rand(1, 100_000);
my $subs = {
'split1' => sub { my $s3 = split1( $s1, $s2 ) },
'mrm_6' => sub { mrm_6( \$s1, \$s2 ); $s1 },
'mrm_7' => sub { mrm_7( \$s1, \$s2 ); $s1 },
'mrm_8' => sub { mrm_8( \$s1, \$s2 ); $s1 },
};
cmpthese( -5, $subs );
use Test::More;
plan 'tests' => scalar keys %{$subs};
my $s3;
foreach my $subname ( keys %{$subs} ) {
my $sub = $subs->{$subname};
if ( defined $s3 ) {
is( $sub->(), $s3, "$subname gets same value" );
}
else {
$s3 = $sub->();
ok( defined $s3, "$subname gets some value" );
}
}
sub split1 {
my ($s1, $s2) = @_;
my @s1 = split //, $s1;
my @s2 = split //, $s2;
foreach my $idx ( 0 .. $#s1 ) {
if ( $s1[$idx] eq chr(0) ) {
$s1[$idx] = $s2[$idx];
}
}
return join '', @s1;
}
sub mrm_6 {
# from mrn_5, testing bytes::misc explicitly instead of importing
# also in-place using of $s2
my ( $s1, $s2 ) = @_;
use bytes ();
my $pos = 0;
while ( -1 < ( $pos = bytes::index( $$s1, '\0', $pos ) ) ) {
bytes::substr( $$s1, $pos, 1, bytes::substr( $$s2, $pos, 1 ) )
+;
}
}
sub mrm_7 {
# from mrn_5, testing bytes::misc explicitly instead of importing
# also in-place using of $s2
my ( $s1, $s2 ) = @_;
use bytes ();
my $pos = 0;
while ( -1 < ( $pos = bytes::index( $$s1, "\000", $pos ) ) ) {
bytes::substr( $$s1, $pos, 1, bytes::substr( $$s2, $pos, 1 ) )
+;
}
}
sub mrm_8 {
# from mrn_5, testing bytes::misc explicitly instead of importing
# also in-place using of $s2
my ( $s1, $s2 ) = @_;
use bytes ();
my $pos = 0;
my $chr = chr 0;
while ( -1 < ( $pos = bytes::index( $$s1, $chr, $pos ) ) ) {
bytes::substr( $$s1, $pos, 1, bytes::substr( $$s2, $pos, 1 ) )
+;
}
}
# This makes sure that $s1 has chr(0)'s in it and $s2 does not.
sub do_rand {
my $min = shift;
my $len = shift;
my $n = "";
for (1 .. $len)
{
$n .= chr( rand(255-$min)+$min );
}
return $n;
}
#sub do_rand {
# my $n = (shift) ? int(rand(255)) : int(rand(254)) + 1;
# return chr( $n );
#}
__END__
If you don't trust Test::More, I guess you could make smaller sample data strings and visually inspect them.
Update:Maybe we should trust Test::More, but take a more carefullook at the tests for the benchmarking and testing code being used from above. | [reply] [d/l] [select] |
You clobber $s1, changing the inputs used for benchmarking and for testing. The $s1 in your test script contains no NULs!
| [reply] [d/l] [select] |
I based this on the results of the Test::More tests that said it was all producing the same output. Apparently, either it's working by some fluke, or the tests are broken.
Something is definitely wrong with the testing. The error shows up when and only when I comment out cmpthese.
Even if I change do_rand to the following to make sure there is always NUL in the returned string:
sub do_rand {
my $min = shift;
my $len = shift;
{
my $n = "";
for (1 .. $len)
{
$n .= chr( rand(255-$min)+$min );
}
if ($min == 0 && $n !~ /\x00/) {
print("REDO!\n");
redo;
}
return $n;
}
}
Updated. | [reply] [d/l] [select] |