0

I want to do an unchecked multiply, so that it does not return an error when multiplying and instead just discard the bits.

code:

102 let count: u64 = (((b + (b >> 4)) & 0xF0F0F0F0F0F0F0Fu64) * 0x101010101010101u64) >> 56;

Error:

thread 'main' panicked at 'attempt to multiply with overflow', src/main.rs:102:22
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

What is the simplest way to do this?

BTW: the algorithm that I am trying to implement is this one: https://stackoverflow.com/a/2709523/20532471

hobrin
  • 3
  • 2
  • 1
    Behold [`unchecked_mul`](https://doc.rust-lang.org/std/primitive.u64.html#method.unchecked_mul)! – tadman Jul 01 '23 at 19:10
  • @tadman if there is a way to do it without having the nightly rust version, that would be great! – hobrin Jul 01 '23 at 19:11
  • 1
    Welcome to SO! Is the CPU that overflows at such multiplication. If you feel brave enough you can create your own multiplication code, likely working with strings instead of numbers. – Ripi2 Jul 01 '23 at 19:12
  • There's other functions in there worth checking out. You could use `overflowing_mul` and just ignore the overflow. – tadman Jul 01 '23 at 19:12
  • @Ripi2 What? Also...what? – tadman Jul 01 '23 at 19:12
  • 5
    @tadman `unchecked_mul` would be undefined behavior since OP *wants* to multiply with overflow. Probably `saturating_mul` or `wrapping_mul` is the answer – kmdreko Jul 01 '23 at 19:12
  • @Ripi2 the entire point of the algorithm is that it is fast. So yeah, unless it is manegable to multiply it using the assembly macro in rust it doesn't make much sense. – hobrin Jul 01 '23 at 19:13
  • @tadman How would you calculate `1234567890123456789 * 9876543210987654321` ? Which bits would you discard? – Ripi2 Jul 01 '23 at 19:14
  • @Ripi2 All the ones that don't fit. This isn't rocket science. Using strings is not the answer here even if you did want to preserve the overflow. A) There's a Rust function for that which "expands" to hold it, and B) Bignum libraries exist. – tadman Jul 01 '23 at 19:14
  • @Ripi2 the most significant bits that are above 64 bit number. Like this is how many bits that number has: log2(1234567890123456789 * 9876543210987654321) = 123.197423777 – hobrin Jul 01 '23 at 19:16
  • Do you just want to do this? https://docs.rs/bitintr/latest/bitintr/trait.Popcnt.html – Simon Goater Jul 01 '23 at 19:18
  • Windows' calculator tells: `1234567890123456789 * 9876543210987654321 = 1,2193263113702179522374638011113e+37` – Ripi2 Jul 01 '23 at 19:19
  • To count the number of `1`'s in a binary representation you can use [R count-ones](https://doc.rust-lang.org/std/primitive.u64.html#method.count_ones) – Ripi2 Jul 01 '23 at 19:21
  • @SimonGoater well yes but actually no. That algorithm that I am trying to implement is actually a subset of another algorithm which uses the internal values of the old algorithm. So yeah. But you don't really need to look at the specific one, I will look into the source of this popcnt library. Source superset algorithm: https://graphics.stanford.edu/~seander/bithacks.html#SelectPosFromMSBRank And then the "Select the bit position" from rank one. – hobrin Jul 01 '23 at 19:23

2 Answers2

5

You do not want unchecked_mul(), you really do not. It causes UB on overflow, while you just want to discard the overflowing bits.

What you need is wrapping_mul():

let count: u64 = (((b + (b >> 4)) & 0xF0F0F0F0F0F0F0Fu64).wrapping_mul(0x101010101010101u64)) >> 56;
Chayim Friedman
  • 47,971
  • 5
  • 48
  • 77
0

I found a quick and dirty workaround. Basically just use a u128 which just about fits all my data that theoretically can be the product, and then convert that back to a u64.

Here is the updated line:

    let count: u64 = ((((b + (b >> 4)) as u128 & 0xF0F0F0F0F0F0F0Fu128) * 0x101010101010101u128) & ((1<<64)-1)) as u64 >> 56;
hobrin
  • 3
  • 2