fnv1a_byte64 Subroutine

private pure subroutine fnv1a_byte64(state, byte_value)

One FNV-1a round: exclusive-or in a byte, then multiply by the prime.

There is no integer kind wider than int64 to compute the product in and mask back, the way the 32-bit round does. Instead the multiply is done modulo 264 directly, using the structure of the prime: 0x100000001B3 is exactly 240 + 435, so

h * prime  =  (h << 40)  +  h * 435        (mod 2**64)

The shift discards the bits that leave the top, which is the reduction modulo 264. The remaining h * 435 is formed on two 32-bit limbs. Each partial product is below 241, so neither can overflow a signed int64, and no carry has to be propagated between them: the low limb’s product is added in whole, and the high limb’s contributes only the 32 bits that have not already left the top of the word. Both additions go through u64_add, which wraps rather than overflowing.

Two multiplies per byte, against the ten a general u64_mul would cost. A 16-bit-limb version with carries is also exact but needs four, and measured 2.18x the cost of the 32-bit hash per byte where this one measures 1.77x (gfortran -O2, 64 MiB, best of three).

Arguments

Type IntentOptional Attributes Name
integer(kind=int64), intent(inout) :: state
integer(kind=int64), intent(in) :: byte_value

A single byte, 0 to 255.


Calls

proc~~fnv1a_byte64~~CallsGraph proc~fnv1a_byte64 fnv1a_byte64 proc~u64_add u64_add proc~fnv1a_byte64->proc~u64_add

Called by

proc~~fnv1a_byte64~~CalledByGraph proc~fnv1a_byte64 fnv1a_byte64 proc~feed_integer64 feed_integer64 proc~feed_integer64->proc~fnv1a_byte64 proc~feed_logical64 feed_logical64 proc~feed_logical64->proc~feed_integer64 proc~feed_real_record64 feed_real_record64 proc~feed_real_record64->proc~feed_integer64 proc~update64_char_0 array_hash64_t%update64_char_0 proc~update64_char_0->proc~feed_integer64 proc~update64_int16_0 array_hash64_t%update64_int16_0 proc~update64_int16_0->proc~feed_integer64 proc~update64_int16_1 array_hash64_t%update64_int16_1 proc~update64_int16_1->proc~feed_integer64 proc~update64_int32_0 array_hash64_t%update64_int32_0 proc~update64_int32_0->proc~feed_integer64 proc~update64_int32_1 array_hash64_t%update64_int32_1 proc~update64_int32_1->proc~feed_integer64 proc~update64_int64_0 array_hash64_t%update64_int64_0 proc~update64_int64_0->proc~feed_integer64 proc~update64_int64_1 array_hash64_t%update64_int64_1 proc~update64_int64_1->proc~feed_integer64 proc~update64_int8_0 array_hash64_t%update64_int8_0 proc~update64_int8_0->proc~feed_integer64 proc~update64_int8_1 array_hash64_t%update64_int8_1 proc~update64_int8_1->proc~feed_integer64 none~update~2 array_hash64_t%update none~update~2->proc~update64_char_0 none~update~2->proc~update64_int16_0 none~update~2->proc~update64_int16_1 none~update~2->proc~update64_int32_0 none~update~2->proc~update64_int32_1 none~update~2->proc~update64_int64_0 none~update~2->proc~update64_int64_1 none~update~2->proc~update64_int8_0 none~update~2->proc~update64_int8_1 proc~update64_logical_0 array_hash64_t%update64_logical_0 none~update~2->proc~update64_logical_0 proc~update64_logical_1 array_hash64_t%update64_logical_1 none~update~2->proc~update64_logical_1 proc~update64_cdp_0 array_hash64_t%update64_cdp_0 none~update~2->proc~update64_cdp_0 proc~update64_cdp_1 array_hash64_t%update64_cdp_1 none~update~2->proc~update64_cdp_1 proc~update64_cdp_2 array_hash64_t%update64_cdp_2 none~update~2->proc~update64_cdp_2 proc~update64_cdp_3 array_hash64_t%update64_cdp_3 none~update~2->proc~update64_cdp_3 proc~update64_char_1 array_hash64_t%update64_char_1 none~update~2->proc~update64_char_1 proc~update64_csp_0 array_hash64_t%update64_csp_0 none~update~2->proc~update64_csp_0 proc~update64_csp_1 array_hash64_t%update64_csp_1 none~update~2->proc~update64_csp_1 proc~update64_csp_2 array_hash64_t%update64_csp_2 none~update~2->proc~update64_csp_2 proc~update64_csp_3 array_hash64_t%update64_csp_3 none~update~2->proc~update64_csp_3 proc~update64_int16_2 array_hash64_t%update64_int16_2 none~update~2->proc~update64_int16_2 proc~update64_int16_3 array_hash64_t%update64_int16_3 none~update~2->proc~update64_int16_3 proc~update64_int32_2 array_hash64_t%update64_int32_2 none~update~2->proc~update64_int32_2 proc~update64_int32_3 array_hash64_t%update64_int32_3 none~update~2->proc~update64_int32_3 proc~update64_int64_2 array_hash64_t%update64_int64_2 none~update~2->proc~update64_int64_2 proc~update64_int64_3 array_hash64_t%update64_int64_3 none~update~2->proc~update64_int64_3 proc~update64_int8_2 array_hash64_t%update64_int8_2 none~update~2->proc~update64_int8_2 proc~update64_int8_3 array_hash64_t%update64_int8_3 none~update~2->proc~update64_int8_3 proc~update64_logical_2 array_hash64_t%update64_logical_2 none~update~2->proc~update64_logical_2 proc~update64_logical_3 array_hash64_t%update64_logical_3 none~update~2->proc~update64_logical_3 proc~update64_rdp_0 array_hash64_t%update64_rdp_0 none~update~2->proc~update64_rdp_0 proc~update64_rdp_1 array_hash64_t%update64_rdp_1 none~update~2->proc~update64_rdp_1 proc~update64_rdp_2 array_hash64_t%update64_rdp_2 none~update~2->proc~update64_rdp_2 proc~update64_rdp_3 array_hash64_t%update64_rdp_3 none~update~2->proc~update64_rdp_3 proc~update64_rsp_0 array_hash64_t%update64_rsp_0 none~update~2->proc~update64_rsp_0 proc~update64_rsp_1 array_hash64_t%update64_rsp_1 none~update~2->proc~update64_rsp_1 proc~update64_rsp_2 array_hash64_t%update64_rsp_2 none~update~2->proc~update64_rsp_2 proc~update64_rsp_3 array_hash64_t%update64_rsp_3 none~update~2->proc~update64_rsp_3 proc~feed_real_dp64 feed_real_dp64 proc~feed_real_dp64->proc~feed_real_record64 proc~feed_real_sp64 feed_real_sp64 proc~feed_real_sp64->proc~feed_real_record64 proc~update64_logical_0->proc~feed_logical64 proc~update64_logical_1->proc~feed_logical64 proc~hash64_cdp_1 hash64_cdp_1 proc~hash64_cdp_1->none~update~2 proc~hash64_cdp_2 hash64_cdp_2 proc~hash64_cdp_2->none~update~2 proc~hash64_cdp_3 hash64_cdp_3 proc~hash64_cdp_3->none~update~2 proc~hash64_char_0 hash64_char_0 proc~hash64_char_0->none~update~2 proc~hash64_char_1 hash64_char_1 proc~hash64_char_1->none~update~2 proc~hash64_csp_1 hash64_csp_1 proc~hash64_csp_1->none~update~2 proc~hash64_csp_2 hash64_csp_2 proc~hash64_csp_2->none~update~2 proc~hash64_csp_3 hash64_csp_3 proc~hash64_csp_3->none~update~2 proc~hash64_int16_1 hash64_int16_1 proc~hash64_int16_1->none~update~2 proc~hash64_int16_2 hash64_int16_2 proc~hash64_int16_2->none~update~2 proc~hash64_int16_3 hash64_int16_3 proc~hash64_int16_3->none~update~2 proc~hash64_int32_1 hash64_int32_1 proc~hash64_int32_1->none~update~2 proc~hash64_int32_2 hash64_int32_2 proc~hash64_int32_2->none~update~2 proc~hash64_int32_3 hash64_int32_3 proc~hash64_int32_3->none~update~2 proc~hash64_int64_1 hash64_int64_1 proc~hash64_int64_1->none~update~2 proc~hash64_int64_2 hash64_int64_2 proc~hash64_int64_2->none~update~2 proc~hash64_int64_3 hash64_int64_3 proc~hash64_int64_3->none~update~2 proc~hash64_int8_1 hash64_int8_1 proc~hash64_int8_1->none~update~2 proc~hash64_int8_2 hash64_int8_2 proc~hash64_int8_2->none~update~2 proc~hash64_int8_3 hash64_int8_3 proc~hash64_int8_3->none~update~2 proc~hash64_logical_1 hash64_logical_1 proc~hash64_logical_1->none~update~2 proc~hash64_logical_2 hash64_logical_2 proc~hash64_logical_2->none~update~2 proc~hash64_logical_3 hash64_logical_3 proc~hash64_logical_3->none~update~2 proc~hash64_rdp_1 hash64_rdp_1 proc~hash64_rdp_1->none~update~2 proc~hash64_rdp_2 hash64_rdp_2 proc~hash64_rdp_2->none~update~2 proc~hash64_rdp_3 hash64_rdp_3 proc~hash64_rdp_3->none~update~2 proc~hash64_rsp_1 hash64_rsp_1 proc~hash64_rsp_1->none~update~2 proc~hash64_rsp_2 hash64_rsp_2 proc~hash64_rsp_2->none~update~2 proc~hash64_rsp_3 hash64_rsp_3 proc~hash64_rsp_3->none~update~2 proc~soa_hash64_int32_field soa_hash64_int32_field proc~soa_hash64_int32_field->none~update~2 proc~soa_hash64_int64_field soa_hash64_int64_field proc~soa_hash64_int64_field->none~update~2 proc~soa_hash64_logical_field soa_hash64_logical_field proc~soa_hash64_logical_field->none~update~2 proc~soa_hash64_real_dp_field soa_hash64_real_dp_field proc~soa_hash64_real_dp_field->none~update~2 proc~soa_hash64_real_sp_field soa_hash64_real_sp_field proc~soa_hash64_real_sp_field->none~update~2 proc~soa_hash_begin_64 soa_hash_begin_64 proc~soa_hash_begin_64->none~update~2 proc~update64_cdp_0->proc~feed_real_dp64 proc~update64_cdp_1->proc~feed_real_dp64 proc~update64_cdp_2->none~update~2 proc~update64_cdp_3->none~update~2 proc~update64_char_1->none~update~2 proc~update64_csp_0->proc~feed_real_sp64 proc~update64_csp_1->proc~feed_real_sp64 proc~update64_csp_2->none~update~2 proc~update64_csp_3->none~update~2 proc~update64_int16_2->none~update~2 proc~update64_int16_3->none~update~2 proc~update64_int32_2->none~update~2 proc~update64_int32_3->none~update~2 proc~update64_int64_2->none~update~2 proc~update64_int64_3->none~update~2 proc~update64_int8_2->none~update~2 proc~update64_int8_3->none~update~2 proc~update64_logical_2->none~update~2 proc~update64_logical_3->none~update~2 proc~update64_rdp_0->proc~feed_real_dp64 proc~update64_rdp_1->proc~feed_real_dp64 proc~update64_rdp_2->none~update~2 proc~update64_rdp_3->none~update~2 proc~update64_rsp_0->proc~feed_real_sp64 proc~update64_rsp_1->proc~feed_real_sp64 proc~update64_rsp_2->none~update~2 proc~update64_rsp_3->none~update~2 interface~array_hash64 array_hash64 interface~array_hash64->proc~hash64_cdp_1 interface~array_hash64->proc~hash64_cdp_2 interface~array_hash64->proc~hash64_cdp_3 interface~array_hash64->proc~hash64_char_0 interface~array_hash64->proc~hash64_char_1 interface~array_hash64->proc~hash64_csp_1 interface~array_hash64->proc~hash64_csp_2 interface~array_hash64->proc~hash64_csp_3 interface~array_hash64->proc~hash64_int16_1 interface~array_hash64->proc~hash64_int16_2 interface~array_hash64->proc~hash64_int16_3 interface~array_hash64->proc~hash64_int32_1 interface~array_hash64->proc~hash64_int32_2 interface~array_hash64->proc~hash64_int32_3 interface~array_hash64->proc~hash64_int64_1 interface~array_hash64->proc~hash64_int64_2 interface~array_hash64->proc~hash64_int64_3 interface~array_hash64->proc~hash64_int8_1 interface~array_hash64->proc~hash64_int8_2 interface~array_hash64->proc~hash64_int8_3 interface~array_hash64->proc~hash64_logical_1 interface~array_hash64->proc~hash64_logical_2 interface~array_hash64->proc~hash64_logical_3 interface~array_hash64->proc~hash64_rdp_1 interface~array_hash64->proc~hash64_rdp_2 interface~array_hash64->proc~hash64_rdp_3 interface~array_hash64->proc~hash64_rsp_1 interface~array_hash64->proc~hash64_rsp_2 interface~array_hash64->proc~hash64_rsp_3 interface~soa_hash_begin soa_hash_begin interface~soa_hash_begin->proc~soa_hash_begin_64 interface~soa_hash_field soa_hash_field interface~soa_hash_field->proc~soa_hash64_int32_field interface~soa_hash_field->proc~soa_hash64_int64_field interface~soa_hash_field->proc~soa_hash64_logical_field interface~soa_hash_field->proc~soa_hash64_real_dp_field interface~soa_hash_field->proc~soa_hash64_real_sp_field

Variables

Type Visibility Attributes Name Initial
integer(kind=int64), private :: h
integer(kind=int64), private :: high
integer(kind=int64), private :: low

Source Code

   pure subroutine fnv1a_byte64(state, byte_value)
      !! One FNV-1a round: exclusive-or in a byte, then multiply by the prime.
      !!
      !! There is no integer kind wider than `int64` to compute the product in
      !! and mask back, the way the 32-bit round does. Instead the multiply is
      !! done modulo 2**64 directly, using the structure of the prime:
      !! 0x100000001B3 is exactly 2**40 + 435, so
      !!
      !! ```
      !! h * prime  =  (h << 40)  +  h * 435        (mod 2**64)
      !! ```
      !!
      !! The shift discards the bits that leave the top, which is the reduction
      !! modulo 2**64. The remaining `h * 435` is formed on two 32-bit limbs.
      !! Each partial product is below 2**41, so neither can overflow a signed
      !! `int64`, and no carry has to be propagated between them: the low
      !! limb's product is added in whole, and the high limb's contributes only
      !! the 32 bits that have not already left the top of the word. Both
      !! additions go through `u64_add`, which wraps rather than overflowing.
      !!
      !! Two multiplies per byte, against the ten a general `u64_mul` would
      !! cost. A 16-bit-limb version with carries is also exact but needs four,
      !! and measured 2.18x the cost of the 32-bit hash per byte where this one
      !! measures 1.77x (gfortran -O2, 64 MiB, best of three).
      integer(int64), intent(inout) :: state
      integer(int64), intent(in) :: byte_value
         !! A single byte, 0 to 255.

      integer(int64) :: h, low, high

      h = ieor(state, byte_value)

      low = iand(h, LIMB_MASK)*FNV64_SMALL
      high = ibits(h, LIMB_BITS, LIMB_BITS)*FNV64_SMALL

      ! The high limb's product is shifted back up, which drops the bits that
      ! leave the top -- part of the same reduction modulo 2**64. `ishft` is
      ! used rather than a multiply because the result may set bit 63, and
      ! reaching that bit arithmetically would be signed overflow.
      state = u64_add(ishft(h, FNV64_SHIFT), &
                      u64_add(low, ishft(iand(high, LIMB_MASK), LIMB_BITS)))
   end subroutine fnv1a_byte64