--- Digest-FNV-XS/XS.pm 2015/10/29 10:56:00 1.1 +++ Digest-FNV-XS/XS.pm 2015/10/29 11:06:39 1.2 @@ -10,7 +10,7 @@ This module is more or less a faster version of L, that additionally supports binary data, incremental hashing, -more FNV variants and xorfolding. The API isn't compatible (and +more FNV variants and more. The API isn't compatible (and neither are the generated hash values. The hash values computed by this module match the official FNV hash values as documented on L). @@ -22,9 +22,9 @@ package Digest::FNV::XS; BEGIN { - $VERSION = 0.01; + $VERSION = 0.02; @ISA = qw(Exporter); - @EXPORT_OK = qw(fnv0_32 fnv0_64 fnv1_32 fnv1a_32 fnv1_64 fnv1a_64); + @EXPORT_OK = qw(fnv0_32 fnv0_64 fnv1_32 fnv1a_32 fnv1_64 fnv1a_64 xorfold_32 xorfold_64 reduce_32 reduce_64); require Exporter; Exporter::export_ok_tags(keys %EXPORT_TAGS); @@ -78,24 +78,15 @@ XOR-folds the 32 (64) bit FNV hash to C<$bits> bits, which can be any value between 1 and 32 (64) inclusive. -XOR-folding is a good method to reduce the FNV hash to a power of two. +XOR-folding is a good method to reduce the FNV hash to a power of two range. =item $hash = Digest::FNV::XS::reduce_32 $hash, $range =item $hash = Digest::FNV::XS::reduce_64 $hash, $range -When you want to reduce a FNV hash value to a rnage that is not a power of -two, you can simply calculate C<$hash % $range>, which creates slightly -biased distribution which nevertheless is completely adequate for many -applications, especially for small C<$range>. - -When a bias is not acceptable, then these two functions can be used to -reduce a 32 (64) but FNV hash to an integer in the range 0 .. C<$range>, -with reduced or nonexistent bias. - -The disadvantage of these functions is that they are slower (and in fact, -have unbounded runtime), although in practise the speed difference in a -Perl program should be negligible. +These two functions can be used to reduce a 32 (64) but FNV hash to +an integer in the range 0 .. C<$range>, using the retry method, which +distributes any bias more evenly. =back @@ -113,6 +104,31 @@ $hash = fnv1a_32 $_, $hash for ...; +=head2 REDUCIDNG THE HASH VALUE + +A common problem is to reduce the 32 (64) bit FNV hash value to a smaller range, +0 .. C<$range>. + +The easiest method to do that, is to mask (For power of two) or modulo +(for other values) the hash value, i.e.: + + $inrage = $hash & ($range - 1) # for $range values that are power of two + $inrage = $hash % $range # for any range + +This is called the lazy mod mapping method, which creates small biases that rarely +cause any problems in practise. + +Nevertheless, you can improve the distribution of the bias by using +I, for power of two ranges (and 32 bit hashews, there is also +C) + + $inrage = Digest::FNV::XS::xorfold_32 $hash, $log2_of_range + +And, using the retry method, for generic ranges (and 32 bit hashes, there +is also C): + + $inrange = Digest::FNX::XS::reduce_32 $hash, $range + =head1 AUTHOR Marc Lehmann