-
-
Save ghadishayban/9bfdc8230cfdcc8f7bad6d3fd8797552 to your computer and use it in GitHub Desktop.
luhn with simd
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package ghadi; | |
import jdk.incubator.vector.*; | |
import java.nio.charset.StandardCharsets; | |
public class SIMDLuhn { | |
// assume that credit cards are 16 digits | |
static final VectorSpecies<Byte> SPECIES = ByteVector.SPECIES_128; | |
/* | |
* calculates luhn check digit from 16 digit string | |
* returns 0 when valid, | |
* set last digit to 0 if calculating checksum | |
*/ | |
static int luhn(String s) { | |
var bs = s.getBytes(StandardCharsets.US_ASCII); | |
var b = ByteVector.fromArray(SPECIES, bs, 0); | |
// decode ascii by subtracting 0x30, which is '0' | |
b = b.sub((byte) 0x30); | |
// double every other element by adding vector to a masked version of itself | |
// 0x5555 = 0101010101010101 | |
b = b.add(b, VectorMask.fromLong(SPECIES, 0x5555)); | |
// subtract 9 from any elements that are > 9 | |
// has effect of adding carry digit 12 => 3, 16 => 7 | |
b = b.sub((byte) 9, b.compare(VectorOperators.GT, (byte) 9)); | |
// horizontal addition across all lanes | |
// add the second half of the vector to the first half, | |
// then the second quarter of the first half to the first quarter, etc | |
// Intel intrinsics include _mm_sad_epu8 to do some of this | |
// but nothing exactly like fold available across platforms | |
b = b.add(b.rearrange(VectorShuffle.fromValues(SPECIES, 8, 9, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0))); | |
b = b.add(b.rearrange(VectorShuffle.fromValues(SPECIES, 4, 5, 6, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0))); | |
b = b.add(b.rearrange(VectorShuffle.fromValues(SPECIES, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0))); | |
b = b.add(b.rearrange(VectorShuffle.fromValues(SPECIES, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0))); | |
// sum is in lane 0 | |
int digit = b.lane(0) % 10; | |
return digit; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment