big: Split up int_is_* comparison tests.

This commit is contained in:
Jeroen van Rijn
2021-08-11 20:59:53 +02:00
parent 777e17d80f
commit fd95f50c56
5 changed files with 353 additions and 262 deletions
+3 -3
View File
@@ -1,10 +1,10 @@
@echo off @echo off
odin run . -vet :odin run . -vet
: -o:size : -o:size
:odin build . -build-mode:shared -show-timings -o:minimal -no-bounds-check :odin build . -build-mode:shared -show-timings -o:minimal -no-bounds-check
:odin build . -build-mode:shared -show-timings -o:size -no-bounds-check :odin build . -build-mode:shared -show-timings -o:size -no-bounds-check
:odin build . -build-mode:shared -show-timings -o:size :odin build . -build-mode:shared -show-timings -o:size
:odin build . -build-mode:shared -show-timings -o:speed -no-bounds-check odin build . -build-mode:shared -show-timings -o:speed -no-bounds-check
:odin build . -build-mode:shared -show-timings -o:speed :odin build . -build-mode:shared -show-timings -o:speed
:python test.py python test.py
+48 -154
View File
@@ -9,199 +9,93 @@ package big
The code started out as an idiomatic source port of libTomMath, which is in the public domain, with thanks. The code started out as an idiomatic source port of libTomMath, which is in the public domain, with thanks.
This file contains various comparison routines. This file contains various comparison routines.
We essentially just check if params are initialized before punting to the `internal_*` versions.
This has the side benefit of being able to add additional characteristics to numbers, like NaN,
and keep support for that contained.
*/ */
import "core:intrinsics" import "core:intrinsics"
import "core:mem"
int_is_initialized :: proc(a: ^Int) -> bool { int_is_initialized :: proc(a: ^Int) -> bool {
if a == nil { if a == nil { return false; }
return false;
} return #force_inline internal_int_is_initialized(a);
raw := transmute(mem.Raw_Dynamic_Array)a.digit;
return raw.cap >= _MIN_DIGIT_COUNT;
} }
int_is_zero :: proc(a: ^Int) -> (res: bool, err: Error) { int_is_zero :: proc(a: ^Int) -> (zero: bool, err: Error) {
if err = clear_if_uninitialized(a); err != nil { if a == nil { return false, .Invalid_Pointer; }
return false, err; if err = clear_if_uninitialized(a); err != nil { return false, err; }
}
return a.used == 0, nil; return #force_inline internal_is_zero(a), nil;
} }
int_is_positive :: proc(a: ^Int) -> (res: bool, err: Error) { int_is_positive :: proc(a: ^Int) -> (positive: bool, err: Error) {
if err = clear_if_uninitialized(a); err != nil { if a == nil { return false, .Invalid_Pointer; }
return false, err; if err = clear_if_uninitialized(a); err != nil { return false, err; }
}
return a.sign == .Zero_or_Positive, nil; return #force_inline internal_is_positive(a), nil;
} }
int_is_negative :: proc(a: ^Int) -> (res: bool, err: Error) { int_is_negative :: proc(a: ^Int) -> (negative: bool, err: Error) {
if err = clear_if_uninitialized(a); err != nil { if a == nil { return false, .Invalid_Pointer; }
return false, err; if err = clear_if_uninitialized(a); err != nil { return false, err; }
}
return a.sign == .Negative, nil; return #force_inline internal_is_negative(a), nil;
} }
int_is_even :: proc(a: ^Int) -> (res: bool, err: Error) { int_is_even :: proc(a: ^Int) -> (even: bool, err: Error) {
if err = clear_if_uninitialized(a); err != nil { if a == nil { return false, .Invalid_Pointer; }
return false, err; if err = clear_if_uninitialized(a); err != nil { return false, err; }
return #force_inline internal_is_even(a), nil;
} }
res, err = is_zero(a); int_is_odd :: proc(a: ^Int) -> (odd: bool, err: Error) {
if err != nil { if a == nil { return false, .Invalid_Pointer; }
return false, err; if err = clear_if_uninitialized(a); err != nil { return false, err; }
} else if res == true {
return true, nil; return #force_inline internal_is_odd(a), nil;
} }
res = false; platform_int_is_power_of_two :: #force_inline proc(a: int) -> bool {
if a.used > 0 && a.digit[0] & 1 == 0 {
res = true;
}
return res, nil;
}
int_is_odd :: proc(a: ^Int) -> (res: bool, err: Error) {
if err = clear_if_uninitialized(a); err != nil {
return false, err;
}
res, err = is_even(a);
return !res, err;
}
platform_int_is_power_of_two :: proc(a: int) -> bool {
return ((a) != 0) && (((a) & ((a) - 1)) == 0); return ((a) != 0) && (((a) & ((a) - 1)) == 0);
} }
int_is_power_of_two :: proc(a: ^Int) -> (res: bool, err: Error) { int_is_power_of_two :: proc(a: ^Int) -> (res: bool, err: Error) {
if err = clear_if_uninitialized(a); err != nil { if a == nil { return false, .Invalid_Pointer; }
return false, err; if err = clear_if_uninitialized(a); err != nil { return false, err; }
}
/* return #force_inline internal_is_power_of_two(a), nil;
Early out for Int == 0.
*/
if a.used == 0 {
return false, nil;
}
/*
For an `Int` to be a power of two, its top limb has to be a power of two.
*/
if !platform_int_is_power_of_two(int(a.digit[a.used - 1])) {
return false, nil;
}
/*
That was the only limb, so it's a power of two.
*/
if a.used == 1 {
return true, nil;
}
/*
For an Int to be a power of two, all limbs except the top one have to be zero.
*/
for i := 1; i < a.used; i += 1 {
if a.digit[i - 1] != 0 {
return false, nil;
}
}
return true, nil;
} }
/* /*
Compare two `Int`s, signed. Compare two `Int`s, signed.
*/ */
int_compare :: proc(a, b: ^Int) -> (res: int, err: Error) { int_compare :: proc(a, b: ^Int) -> (comparison: int, err: Error) {
if err = clear_if_uninitialized(a); err != nil { if a == nil || b == nil { return 0, .Invalid_Pointer; }
return 0, err; if err = clear_if_uninitialized(a, b); err != nil { return 0, err; }
}
if err = clear_if_uninitialized(b); err != nil {
return 0, err;
}
neg: bool; return #force_inline internal_cmp(a, b), nil;
if neg, err = is_negative(a); err != nil {
return 0, err;
}
/* Compare based on sign */
if a.sign != b.sign {
res = -1 if neg else +1;
return res, nil;
}
/* If negative, compare in the opposite direction */
if neg {
return cmp_mag(b, a);
}
return cmp_mag(a, b);
} }
int_cmp :: int_compare;
/* /*
Compare an `Int` to an unsigned number upto the size of the backing type. Compare an `Int` to an unsigned number upto the size of the backing type.
*/ */
int_compare_digit :: proc(a: ^Int, u: DIGIT) -> (res: int, err: Error) { int_compare_digit :: proc(a: ^Int, b: DIGIT) -> (comparison: int, err: Error) {
if err = clear_if_uninitialized(a); err != nil { if a == nil { return 0, .Invalid_Pointer; }
return 0, err; if err = clear_if_uninitialized(a); err != nil { return 0, err; }
}
/* Compare based on sign */ return #force_inline internal_cmp_digit(a, b), nil;
neg: bool;
if neg, err = is_neg(a); err != nil {
return 0, err;
}
if neg {
return -1, nil;
}
/* Compare based on magnitude */
if a.used > 1 {
return +1, nil;
}
/* Compare the only digit in `a` to `u`. */
if a.digit[0] != u {
if a.digit[0] > u {
return +1, nil;
}
return -1, nil;
}
return 0, nil;
} }
/* /*
Compare the magnitude of two `Int`s, unsigned. Compare the magnitude of two `Int`s, unsigned.
*/ */
int_compare_magnitude :: proc(a, b: ^Int) -> (res: int, err: Error) { int_compare_magnitude :: proc(a, b: ^Int) -> (res: int, err: Error) {
if err = clear_if_uninitialized(a); err != nil { if a == nil || b == nil { return 0, .Invalid_Pointer; }
return 0, err; if err = clear_if_uninitialized(a, b); err != nil { return 0, err; }
}
if err = clear_if_uninitialized(b); err != nil {
return 0, err;
}
/* Compare based on used digits */ return #force_inline internal_cmp_mag(a, b), nil;
if a.used != b.used {
if a.used > b.used {
return +1, nil;
}
return -1, nil;
}
/* Same number of used digits, compare based on their value */
for n := a.used - 1; n >= 0; n -= 1 {
if a.digit[n] != b.digit[n] {
if a.digit[n] > b.digit[n] {
return +1, nil;
}
return -1, nil;
}
}
return 0, nil;
} }
+6 -10
View File
@@ -75,16 +75,12 @@ demo :: proc() {
a, b, c, d, e, f := &Int{}, &Int{}, &Int{}, &Int{}, &Int{}, &Int{}; a, b, c, d, e, f := &Int{}, &Int{}, &Int{}, &Int{}, &Int{}, &Int{};
defer destroy(a, b, c, d, e, f); defer destroy(a, b, c, d, e, f);
n := 1_024; power_of_two(a, 3112);
k := 3; fmt.printf("a is power of two: %v\n", internal_is_power_of_two(a));
sub(a, a, 1);
{ fmt.printf("a is power of two: %v\n", internal_is_power_of_two(a));
SCOPED_TIMING(.choose); add(a, a, 1);
choose(a, n, k); fmt.printf("a is power of two: %v\n", internal_is_power_of_two(a));
}
fmt.printf("%v choose %v ", n, k);
print("= ", a);
} }
main :: proc() { main :: proc() {
+241 -1
View File
@@ -25,6 +25,8 @@ package big
Exceptions include `quotient` and `remainder`, which are allowed to be `nil` when the calling code doesn't need them. Exceptions include `quotient` and `remainder`, which are allowed to be `nil` when the calling code doesn't need them.
Check the comments above each `internal_*` implementation to see what constraints it expects to have met. Check the comments above each `internal_*` implementation to see what constraints it expects to have met.
TODO: Handle +/- Infinity and NaN.
*/ */
import "core:mem" import "core:mem"
@@ -107,6 +109,7 @@ internal_int_add_unsigned :: proc(dest, a, b: ^Int, allocator := context.allocat
*/ */
return clamp(dest); return clamp(dest);
} }
internal_add_unsigned :: proc { internal_int_add_unsigned, };
/* /*
Low-level addition, signed. Handbook of Applied Cryptography, algorithm 14.7. Low-level addition, signed. Handbook of Applied Cryptography, algorithm 14.7.
@@ -136,6 +139,7 @@ internal_int_add_signed :: proc(dest, a, b: ^Int, allocator := context.allocator
dest.sign = x.sign; dest.sign = x.sign;
return #force_inline internal_int_sub_unsigned(dest, x, y, allocator); return #force_inline internal_int_sub_unsigned(dest, x, y, allocator);
} }
internal_add_signed :: proc { internal_int_add_signed, };
/* /*
Low-level addition Int+DIGIT, signed. Handbook of Applied Cryptography, algorithm 14.7. Low-level addition Int+DIGIT, signed. Handbook of Applied Cryptography, algorithm 14.7.
@@ -246,7 +250,6 @@ internal_int_add_digit :: proc(dest, a: ^Int, digit: DIGIT) -> (err: Error) {
*/ */
return clamp(dest); return clamp(dest);
} }
internal_add :: proc { internal_int_add_signed, internal_int_add_digit, }; internal_add :: proc { internal_int_add_signed, internal_int_add_digit, };
/* /*
@@ -314,6 +317,7 @@ internal_int_sub_unsigned :: proc(dest, number, decrease: ^Int, allocator := con
*/ */
return clamp(dest); return clamp(dest);
} }
internal_sub_unsigned :: proc { internal_int_sub_unsigned, };
/* /*
Low-level subtraction, signed. Handbook of Applied Cryptography, algorithm 14.9. Low-level subtraction, signed. Handbook of Applied Cryptography, algorithm 14.9.
@@ -915,6 +919,204 @@ internal_int_mod_bits :: proc(remainder, numerator: ^Int, bits: int) -> (err: Er
return clamp(remainder); return clamp(remainder);
} }
/*
============================= Low-level helpers =============================
`internal_*` helpers don't return an `Error` like their public counterparts do,
because they expect not to be passed `nil` or uninitialized inputs.
This makes them more suitable for `internal_*` functions and some of the
public ones that have already satisfied these constraints.
*/
/*
This procedure will return `true` if the `Int` is initialized, `false` if not.
Assumes `a` not to be `nil`.
*/
internal_int_is_initialized :: #force_inline proc(a: ^Int) -> (initialized: bool) {
raw := transmute(mem.Raw_Dynamic_Array)a.digit;
return raw.cap >= _MIN_DIGIT_COUNT;
}
internal_is_initialized :: proc { internal_int_is_initialized, };
/*
This procedure will return `true` if the `Int` is zero, `false` if not.
Assumes `a` not to be `nil`.
*/
internal_int_is_zero :: #force_inline proc(a: ^Int) -> (zero: bool) {
return a.used == 0;
}
internal_is_zero :: proc { internal_int_is_zero, };
/*
This procedure will return `true` if the `Int` is positive, `false` if not.
Assumes `a` not to be `nil`.
*/
internal_int_is_positive :: #force_inline proc(a: ^Int) -> (positive: bool) {
return a.sign == .Zero_or_Positive;
}
internal_is_positive :: proc { internal_int_is_positive, };
/*
This procedure will return `true` if the `Int` is negative, `false` if not.
Assumes `a` not to be `nil`.
*/
internal_int_is_negative :: #force_inline proc(a: ^Int) -> (negative: bool) {
return a.sign == .Negative;
}
internal_is_negative :: proc { internal_int_is_negative, };
/*
This procedure will return `true` if the `Int` is even, `false` if not.
Assumes `a` not to be `nil`.
*/
internal_int_is_even :: #force_inline proc(a: ^Int) -> (even: bool) {
if internal_is_zero(a) { return true; }
/*
`a.used` > 0 here, because the above handled `is_zero`.
We don't need to explicitly test it.
*/
return a.digit[0] & 1 == 0;
}
internal_is_even :: proc { internal_int_is_even, };
/*
This procedure will return `true` if the `Int` is even, `false` if not.
Assumes `a` not to be `nil`.
*/
internal_int_is_odd :: #force_inline proc(a: ^Int) -> (odd: bool) {
return !internal_int_is_even(a);
}
internal_is_odd :: proc { internal_int_is_odd, };
/*
This procedure will return `true` if the `Int` is a power of two, `false` if not.
Assumes `a` not to be `nil`.
*/
internal_int_is_power_of_two :: #force_inline proc(a: ^Int) -> (power_of_two: bool) {
/*
Early out for Int == 0.
*/
if #force_inline internal_is_zero(a) { return true; }
/*
For an `Int` to be a power of two, its bottom limb has to be a power of two.
*/
if ! #force_inline platform_int_is_power_of_two(int(a.digit[a.used - 1])) { return false; }
/*
We've established that the bottom limb is a power of two.
If it's the only limb, that makes the entire Int a power of two.
*/
if a.used == 1 { return true; }
/*
For an `Int` to be a power of two, all limbs except the top one have to be zero.
*/
for i := 1; i < a.used && a.digit[i - 1] != 0; i += 1 { return false; }
return true;
}
internal_is_power_of_two :: proc { internal_int_is_power_of_two, };
/*
Compare two `Int`s, signed.
Returns -1 if `a` < `b`, 0 if `a` == `b` and 1 if `b` > `a`.
Expects `a` and `b` both to be valid `Int`s, i.e. initialized and not `nil`.
*/
internal_int_compare :: #force_inline proc(a, b: ^Int) -> (comparison: int) {
a_is_negative := #force_inline internal_is_negative(a);
/*
Compare based on sign.
*/
if a.sign != b.sign { return -1 if a_is_negative else +1; }
/*
If `a` is negative, compare in the opposite direction */
if a_is_negative { return #force_inline internal_compare_magnitude(b, a); }
return #force_inline internal_compare_magnitude(a, b);
}
internal_compare :: proc { internal_int_compare, internal_int_compare_digit, };
internal_cmp :: internal_compare;
/*
Compare an `Int` to an unsigned number upto the size of the backing type.
Returns -1 if `a` < `b`, 0 if `a` == `b` and 1 if `b` > `a`.
Expects `a` and `b` both to be valid `Int`s, i.e. initialized and not `nil`.
*/
internal_int_compare_digit :: #force_inline proc(a: ^Int, b: DIGIT) -> (comparison: int) {
/*
Compare based on sign.
*/
if #force_inline internal_is_negative(a) { return -1; }
/*
Compare based on magnitude.
*/
if a.used > 1 { return +1; }
/*
Compare the only digit in `a` to `b`.
*/
switch {
case a.digit[0] < b:
return -1;
case a.digit[0] == b:
return 0;
case a.digit[0] > b:
return +1;
case:
/*
Unreachable.
Just here because Odin complains about a missing return value at the bottom of the proc otherwise.
*/
return;
}
}
internal_compare_digit :: proc { internal_int_compare_digit, };
internal_cmp_digit :: internal_compare_digit;
/*
Compare the magnitude of two `Int`s, unsigned.
*/
internal_int_compare_magnitude :: #force_inline proc(a, b: ^Int) -> (comparison: int) {
/*
Compare based on used digits.
*/
if a.used != b.used {
if a.used > b.used {
return +1;
}
return -1;
}
/*
Same number of used digits, compare based on their value.
*/
#no_bounds_check for n := a.used - 1; n >= 0; n -= 1 {
if a.digit[n] != b.digit[n] {
if a.digit[n] > b.digit[n] {
return +1;
}
return -1;
}
}
return 0;
}
internal_compare_magnitude :: proc { internal_int_compare_magnitude, };
internal_cmp_mag :: internal_compare_magnitude;
internal_int_zero_unused :: #force_inline proc(dest: ^Int, old_used := -1) { internal_int_zero_unused :: #force_inline proc(dest: ^Int, old_used := -1) {
/* /*
If we don't pass the number of previously used DIGITs, we zero all remaining ones. If we don't pass the number of previously used DIGITs, we zero all remaining ones.
@@ -1689,6 +1891,44 @@ _private_int_gcd_lcm :: proc(res_gcd, res_lcm, a, b: ^Int) -> (err: Error) {
Tables used by `internal_*` and `_*`. Tables used by `internal_*` and `_*`.
*/ */
_private_prime_table := []DIGIT{
0x0002, 0x0003, 0x0005, 0x0007, 0x000B, 0x000D, 0x0011, 0x0013,
0x0017, 0x001D, 0x001F, 0x0025, 0x0029, 0x002B, 0x002F, 0x0035,
0x003B, 0x003D, 0x0043, 0x0047, 0x0049, 0x004F, 0x0053, 0x0059,
0x0061, 0x0065, 0x0067, 0x006B, 0x006D, 0x0071, 0x007F, 0x0083,
0x0089, 0x008B, 0x0095, 0x0097, 0x009D, 0x00A3, 0x00A7, 0x00AD,
0x00B3, 0x00B5, 0x00BF, 0x00C1, 0x00C5, 0x00C7, 0x00D3, 0x00DF,
0x00E3, 0x00E5, 0x00E9, 0x00EF, 0x00F1, 0x00FB, 0x0101, 0x0107,
0x010D, 0x010F, 0x0115, 0x0119, 0x011B, 0x0125, 0x0133, 0x0137,
0x0139, 0x013D, 0x014B, 0x0151, 0x015B, 0x015D, 0x0161, 0x0167,
0x016F, 0x0175, 0x017B, 0x017F, 0x0185, 0x018D, 0x0191, 0x0199,
0x01A3, 0x01A5, 0x01AF, 0x01B1, 0x01B7, 0x01BB, 0x01C1, 0x01C9,
0x01CD, 0x01CF, 0x01D3, 0x01DF, 0x01E7, 0x01EB, 0x01F3, 0x01F7,
0x01FD, 0x0209, 0x020B, 0x021D, 0x0223, 0x022D, 0x0233, 0x0239,
0x023B, 0x0241, 0x024B, 0x0251, 0x0257, 0x0259, 0x025F, 0x0265,
0x0269, 0x026B, 0x0277, 0x0281, 0x0283, 0x0287, 0x028D, 0x0293,
0x0295, 0x02A1, 0x02A5, 0x02AB, 0x02B3, 0x02BD, 0x02C5, 0x02CF,
0x02D7, 0x02DD, 0x02E3, 0x02E7, 0x02EF, 0x02F5, 0x02F9, 0x0301,
0x0305, 0x0313, 0x031D, 0x0329, 0x032B, 0x0335, 0x0337, 0x033B,
0x033D, 0x0347, 0x0355, 0x0359, 0x035B, 0x035F, 0x036D, 0x0371,
0x0373, 0x0377, 0x038B, 0x038F, 0x0397, 0x03A1, 0x03A9, 0x03AD,
0x03B3, 0x03B9, 0x03C7, 0x03CB, 0x03D1, 0x03D7, 0x03DF, 0x03E5,
0x03F1, 0x03F5, 0x03FB, 0x03FD, 0x0407, 0x0409, 0x040F, 0x0419,
0x041B, 0x0425, 0x0427, 0x042D, 0x043F, 0x0443, 0x0445, 0x0449,
0x044F, 0x0455, 0x045D, 0x0463, 0x0469, 0x047F, 0x0481, 0x048B,
0x0493, 0x049D, 0x04A3, 0x04A9, 0x04B1, 0x04BD, 0x04C1, 0x04C7,
0x04CD, 0x04CF, 0x04D5, 0x04E1, 0x04EB, 0x04FD, 0x04FF, 0x0503,
0x0509, 0x050B, 0x0511, 0x0515, 0x0517, 0x051B, 0x0527, 0x0529,
0x052F, 0x0551, 0x0557, 0x055D, 0x0565, 0x0577, 0x0581, 0x058F,
0x0593, 0x0595, 0x0599, 0x059F, 0x05A7, 0x05AB, 0x05AD, 0x05B3,
0x05BF, 0x05C9, 0x05CB, 0x05CF, 0x05D1, 0x05D5, 0x05DB, 0x05E7,
0x05F3, 0x05FB, 0x0607, 0x060D, 0x0611, 0x0617, 0x061F, 0x0623,
0x062B, 0x062F, 0x063D, 0x0641, 0x0647, 0x0649, 0x064D, 0x0653,
};
when MATH_BIG_FORCE_64_BIT || (!MATH_BIG_FORCE_32_BIT && size_of(rawptr) == 8) { when MATH_BIG_FORCE_64_BIT || (!MATH_BIG_FORCE_32_BIT && size_of(rawptr) == 8) {
_factorial_table := [35]_WORD{ _factorial_table := [35]_WORD{
/* f(00): */ 1, /* f(00): */ 1,
+1 -40
View File
@@ -18,7 +18,7 @@ package big
int_prime_is_divisible :: proc(a: ^Int) -> (res: bool, err: Error) { int_prime_is_divisible :: proc(a: ^Int) -> (res: bool, err: Error) {
rem: DIGIT; rem: DIGIT;
for prime in _PRIME_TABLE { for prime in _private_prime_table {
if rem, err = mod(a, prime); err != nil { return false, err; } if rem, err = mod(a, prime); err != nil { return false, err; }
if rem == 0 { return true, nil; } if rem == 0 { return true, nil; }
} }
@@ -27,42 +27,3 @@ int_prime_is_divisible :: proc(a: ^Int) -> (res: bool, err: Error) {
*/ */
return false, nil; return false, nil;
} }
_PRIME_TABLE := []DIGIT{
0x0002, 0x0003, 0x0005, 0x0007, 0x000B, 0x000D, 0x0011, 0x0013,
0x0017, 0x001D, 0x001F, 0x0025, 0x0029, 0x002B, 0x002F, 0x0035,
0x003B, 0x003D, 0x0043, 0x0047, 0x0049, 0x004F, 0x0053, 0x0059,
0x0061, 0x0065, 0x0067, 0x006B, 0x006D, 0x0071, 0x007F, 0x0083,
0x0089, 0x008B, 0x0095, 0x0097, 0x009D, 0x00A3, 0x00A7, 0x00AD,
0x00B3, 0x00B5, 0x00BF, 0x00C1, 0x00C5, 0x00C7, 0x00D3, 0x00DF,
0x00E3, 0x00E5, 0x00E9, 0x00EF, 0x00F1, 0x00FB, 0x0101, 0x0107,
0x010D, 0x010F, 0x0115, 0x0119, 0x011B, 0x0125, 0x0133, 0x0137,
0x0139, 0x013D, 0x014B, 0x0151, 0x015B, 0x015D, 0x0161, 0x0167,
0x016F, 0x0175, 0x017B, 0x017F, 0x0185, 0x018D, 0x0191, 0x0199,
0x01A3, 0x01A5, 0x01AF, 0x01B1, 0x01B7, 0x01BB, 0x01C1, 0x01C9,
0x01CD, 0x01CF, 0x01D3, 0x01DF, 0x01E7, 0x01EB, 0x01F3, 0x01F7,
0x01FD, 0x0209, 0x020B, 0x021D, 0x0223, 0x022D, 0x0233, 0x0239,
0x023B, 0x0241, 0x024B, 0x0251, 0x0257, 0x0259, 0x025F, 0x0265,
0x0269, 0x026B, 0x0277, 0x0281, 0x0283, 0x0287, 0x028D, 0x0293,
0x0295, 0x02A1, 0x02A5, 0x02AB, 0x02B3, 0x02BD, 0x02C5, 0x02CF,
0x02D7, 0x02DD, 0x02E3, 0x02E7, 0x02EF, 0x02F5, 0x02F9, 0x0301,
0x0305, 0x0313, 0x031D, 0x0329, 0x032B, 0x0335, 0x0337, 0x033B,
0x033D, 0x0347, 0x0355, 0x0359, 0x035B, 0x035F, 0x036D, 0x0371,
0x0373, 0x0377, 0x038B, 0x038F, 0x0397, 0x03A1, 0x03A9, 0x03AD,
0x03B3, 0x03B9, 0x03C7, 0x03CB, 0x03D1, 0x03D7, 0x03DF, 0x03E5,
0x03F1, 0x03F5, 0x03FB, 0x03FD, 0x0407, 0x0409, 0x040F, 0x0419,
0x041B, 0x0425, 0x0427, 0x042D, 0x043F, 0x0443, 0x0445, 0x0449,
0x044F, 0x0455, 0x045D, 0x0463, 0x0469, 0x047F, 0x0481, 0x048B,
0x0493, 0x049D, 0x04A3, 0x04A9, 0x04B1, 0x04BD, 0x04C1, 0x04C7,
0x04CD, 0x04CF, 0x04D5, 0x04E1, 0x04EB, 0x04FD, 0x04FF, 0x0503,
0x0509, 0x050B, 0x0511, 0x0515, 0x0517, 0x051B, 0x0527, 0x0529,
0x052F, 0x0551, 0x0557, 0x055D, 0x0565, 0x0577, 0x0581, 0x058F,
0x0593, 0x0595, 0x0599, 0x059F, 0x05A7, 0x05AB, 0x05AD, 0x05B3,
0x05BF, 0x05C9, 0x05CB, 0x05CF, 0x05D1, 0x05D5, 0x05DB, 0x05E7,
0x05F3, 0x05FB, 0x0607, 0x060D, 0x0611, 0x0617, 0x061F, 0x0623,
0x062B, 0x062F, 0x063D, 0x0641, 0x0647, 0x0649, 0x064D, 0x0653,
};