I tried to code up a quick and dirty way to use Cantor Pairing with
integers instead of just unsigned. Using a mapping from Moebius in a different thread vs traditional unsigned Cantor.
Its funny... His mapping is giving me different numbers for when the
pair is two positive integers.
____________
ct_cantor_integer::manifest()
Input Pair: (47, 32)
=== Traditional Unsigned Cantor ===
Resulting Index: 3192
Unpacked Pair: (47, 32)
Verification: SUCCESS
=== Moebius Interleaved Signed Cantor ===
Intermediate Nat Index: 12625
Final Mapping (Z): -6313
Unpacked Pair: (47, 32)
Verification: SUCCESS
____________
Here is 3 and 4:
____________
ct_cantor_integer::manifest()
Input Pair: (3, 4)
=== Traditional Unsigned Cantor ===
Resulting Index: 32
Unpacked Pair: (3, 4)
Verification: SUCCESS
=== Moebius Interleaved Signed Cantor ===
Intermediate Nat Index: 113
Final Mapping (Z): -57
Unpacked Pair: (3, 4)
Verification: SUCCESS
____________
Okay, here is a run using a pair of (-11, 15)... Traditional Cantor
Pairing does not like that too much?
Oh it failed, but the integer map worked:
____________
ct_cantor_integer::manifest()
Input Pair: (-11, 15)
=== Traditional Unsigned Cantor ===
Resulting Index: 25
Unpacked Pair: (2, 4)
Verification: FAILED
=== Moebius Interleaved Signed Cantor ===
Intermediate Nat Index: 1356
Final Mapping (Z): 678
Unpacked Pair: (-11, 15)
Verification: SUCCESS
____________
Here is (42, 42), the both should work:
____________
ct_cantor_integer::manifest()
Input Pair: (42, 42)
=== Traditional Unsigned Cantor ===
Resulting Index: 3612
Unpacked Pair: (42, 42)
Verification: SUCCESS
=== Moebius Interleaved Signed Cantor ===
Intermediate Nat Index: 14280
Final Mapping (Z): 7140
Unpacked Pair: (42, 42)
Verification: SUCCESS
____________
Interesting!
Fwiw, here is my crude code:
________________________________
// For Moebius
// Quick and crude Cantor mapper.
// Works with integers, I think.
// When all the components are positive I can use
// traditional Cantor Pairing...
namespace ct_cantor_integer
{
struct cantor_pair
{
int m_a;
int m_b;
};
// Fold a signed integer Z into a natural number N
unsigned long long
fold_z_to_n(
int z
) {
if (z >= 0)
{
return 2ULL * static_cast<unsigned long long>(z);
}
else
{
long long positive_result = -2LL * static_cast<long
long>(z) - 1LL;
return static_cast<unsigned long long>(positive_result);
}
}
// Unfold a natural number N back into a signed integer Z
int
unfold_n_to_z(
unsigned long long n
) {
if (n % 2 == 0)
{
return static_cast<int>(n / 2ULL);
}
else
{
return static_cast<int>(-static_cast<long long>((n + 1ULL)
/ 2ULL));
}
}
// Pure, traditional unsigned Cantor pairing baseline
unsigned long long
traditional_pack(
unsigned int x,
unsigned int y
) {
unsigned long long sum = x + y;
return (sum * (sum + 1ULL)) / 2ULL + y;
}
// Traditional unsigned Cantor unpacker
cantor_pair
traditional_unpack(
unsigned long long w
) {
unsigned long long t = static_cast<unsigned long long>((std::sqrt(static_cast<double>(8ULL * w + 1ULL)) - 1.0) / 2.0);
unsigned long long tri = (t * (t + 1ULL)) / 2ULL;
unsigned long long Y = w - tri;
unsigned long long X = t - Y;
return { static_cast<int>(X), static_cast<int>(Y) };
}
// Pack two signed integers into a single unique natural number
(Moebius phase 1)
unsigned long long
pack_pair_signed(
int a,
int b
) {
unsigned long long X = fold_z_to_n(a);
unsigned long long Y = fold_z_to_n(b);
unsigned long long sum = X + Y;
return (sum * (sum + 1ULL)) / 2ULL + Y;
}
// Unpack a single natural number back into a pair of signed
integers (Moebius phase 2)
cantor_pair unpack_seed_signed(
unsigned long long w
) {
unsigned long long t = static_cast<unsigned long long>((std::sqrt(static_cast<double>(8ULL * w + 1ULL)) - 1.0) / 2.0);
unsigned long long tri = (t * (t + 1ULL)) / 2ULL;
unsigned long long Y = w - tri;
unsigned long long X = t - Y;
return { unfold_n_to_z(X), unfold_n_to_z(Y) };
}
void
manifest()
{
std::cout << "ct_cantor_integer::manifest()\n";
// Testing purely positive inputs to allow comparison with traditional
int orig_a = 47;
int orig_b = 32;
std::cout << " Input Pair: (" << orig_a << ", " << orig_b << ")\n\n";
// =====================================================================
// TRADITIONAL UNSIGNED CANTOR PIPELINE
// =====================================================================
unsigned long long trad_index = traditional_pack(orig_a, orig_b);
cantor_pair trad_recovered = traditional_unpack(trad_index);
std::cout << " === Traditional Unsigned Cantor ===\n";
std::cout << " Resulting Index: " << trad_index << "\n";
std::cout << " Unpacked Pair: (" << trad_recovered.m_a
<< ", " << trad_recovered.m_b << ")\n";
if (trad_recovered.m_a == orig_a && trad_recovered.m_b ==
orig_b) {
std::cout << " Verification: SUCCESS\n\n";
}
else {
std::cout << " Verification: FAILED\n\n";
}
// =====================================================================
// MOEBIUS INTERLEAVED SIGNED PIPELINE
// =====================================================================
unsigned long long moebius_nat_index = pack_pair_signed(orig_a, orig_b);
int moebius_final_integer = unfold_n_to_z(moebius_nat_index);
// Reverse the mapping pipeline entirely
unsigned long long moebius_recovered_nat = fold_z_to_n(moebius_final_integer);
cantor_pair moebius_recovered_pair = unpack_seed_signed(moebius_recovered_nat);
std::cout << " === Moebius Interleaved Signed Cantor ===\n";
std::cout << " Intermediate Nat Index: " <<
moebius_nat_index << "\n";
std::cout << " Final Mapping (Z): " << moebius_final_integer << "\n";
std::cout << " Unpacked Pair: (" << moebius_recovered_pair.m_a << ", " << moebius_recovered_pair.m_b << ")\n";
if (moebius_recovered_pair.m_a == orig_a && moebius_recovered_pair.m_b == orig_b) {
std::cout << " Verification: SUCCESS\n";
}
else {
std::cout << " Verification: FAILED\n";
}
}
}
________________________________
any thoughts? Thanks everybody! :^)
On 06/09/2026 03:33 PM, Chris M. Thomasson wrote:
I tried to code up a quick and dirty way to use Cantor Pairing with
integers instead of just unsigned. Using a mapping from Moebius in a
different thread vs traditional unsigned Cantor.
Its funny... His mapping is giving me different numbers for when the
pair is two positive integers.
____________
ct_cantor_integer::manifest()
-a-a Input Pair: (47, 32)
-a-a === Traditional Unsigned Cantor ===
-a-a-a-a Resulting Index:-a-a 3192
-a-a-a-a Unpacked Pair:-a-a-a-a (47, 32)
-a-a-a-a Verification:-a-a-a-a-a SUCCESS
-a-a === Moebius Interleaved Signed Cantor ===
-a-a-a-a Intermediate Nat Index: 12625
-a-a-a-a Final Mapping (Z):-a-a-a-a-a-a -6313
-a-a-a-a Unpacked Pair:-a-a-a-a-a-a-a-a-a-a (47, 32)
-a-a-a-a Verification:-a-a-a-a-a-a-a-a-a-a-a SUCCESS
____________
Here is 3 and 4:
____________
ct_cantor_integer::manifest()
-a-a Input Pair: (3, 4)
-a-a === Traditional Unsigned Cantor ===
-a-a-a-a Resulting Index:-a-a 32
-a-a-a-a Unpacked Pair:-a-a-a-a (3, 4)
-a-a-a-a Verification:-a-a-a-a-a SUCCESS
-a-a === Moebius Interleaved Signed Cantor ===
-a-a-a-a Intermediate Nat Index: 113
-a-a-a-a Final Mapping (Z):-a-a-a-a-a-a -57
-a-a-a-a Unpacked Pair:-a-a-a-a-a-a-a-a-a-a (3, 4)
-a-a-a-a Verification:-a-a-a-a-a-a-a-a-a-a-a SUCCESS
____________
Okay, here is a run using a pair of (-11, 15)... Traditional Cantor
Pairing does not like that too much?
Oh it failed, but the integer map worked:
____________
ct_cantor_integer::manifest()
-a-a Input Pair: (-11, 15)
-a-a === Traditional Unsigned Cantor ===
-a-a-a-a Resulting Index:-a-a 25
-a-a-a-a Unpacked Pair:-a-a-a-a (2, 4)
-a-a-a-a Verification:-a-a-a-a-a FAILED
-a-a === Moebius Interleaved Signed Cantor ===
-a-a-a-a Intermediate Nat Index: 1356
-a-a-a-a Final Mapping (Z):-a-a-a-a-a-a 678
-a-a-a-a Unpacked Pair:-a-a-a-a-a-a-a-a-a-a (-11, 15)
-a-a-a-a Verification:-a-a-a-a-a-a-a-a-a-a-a SUCCESS
____________
Here is (42, 42), the both should work:
____________
ct_cantor_integer::manifest()
-a-a Input Pair: (42, 42)
-a-a === Traditional Unsigned Cantor ===
-a-a-a-a Resulting Index:-a-a 3612
-a-a-a-a Unpacked Pair:-a-a-a-a (42, 42)
-a-a-a-a Verification:-a-a-a-a-a SUCCESS
-a-a === Moebius Interleaved Signed Cantor ===
-a-a-a-a Intermediate Nat Index: 14280
-a-a-a-a Final Mapping (Z):-a-a-a-a-a-a 7140
-a-a-a-a Unpacked Pair:-a-a-a-a-a-a-a-a-a-a (42, 42)
-a-a-a-a Verification:-a-a-a-a-a-a-a-a-a-a-a SUCCESS
____________
Interesting!
Fwiw, here is my crude code:
________________________________
// For Moebius
// Quick and crude Cantor mapper.
// Works with integers, I think.
// When all the components are positive I can use
// traditional Cantor Pairing...
namespace ct_cantor_integer
{
-a-a-a-a struct cantor_pair
-a-a-a-a {
-a-a-a-a-a-a-a-a int m_a;
-a-a-a-a-a-a-a-a int m_b;
-a-a-a-a };
-a-a-a-a // Fold a signed integer Z into a natural number N
-a-a-a-a unsigned long long
-a-a-a-a fold_z_to_n(
-a-a-a-a-a-a-a-a int z
-a-a-a-a ) {
-a-a-a-a-a-a-a-a if (z >= 0)
-a-a-a-a-a-a-a-a {
-a-a-a-a-a-a-a-a-a-a-a-a return 2ULL * static_cast<unsigned long long>(z); >> -a-a-a-a-a-a-a-a }
-a-a-a-a-a-a-a-a else
-a-a-a-a-a-a-a-a {
-a-a-a-a-a-a-a-a-a-a-a-a long long positive_result = -2LL * static_cast<long >> long>(z) - 1LL;
-a-a-a-a-a-a-a-a-a-a-a-a return static_cast<unsigned long long>(positive_result);
-a-a-a-a-a-a-a-a }
-a-a-a-a }
-a-a-a-a // Unfold a natural number N back into a signed integer Z
-a-a-a-a int
-a-a-a-a unfold_n_to_z(
-a-a-a-a-a-a-a-a unsigned long long n
-a-a-a-a ) {
-a-a-a-a-a-a-a-a if (n % 2 == 0)
-a-a-a-a-a-a-a-a {
-a-a-a-a-a-a-a-a-a-a-a-a return static_cast<int>(n / 2ULL);
-a-a-a-a-a-a-a-a }
-a-a-a-a-a-a-a-a else
-a-a-a-a-a-a-a-a {
-a-a-a-a-a-a-a-a-a-a-a-a return static_cast<int>(-static_cast<long long>((n + 1ULL)
/ 2ULL));
-a-a-a-a-a-a-a-a }
-a-a-a-a }
-a-a-a-a // Pure, traditional unsigned Cantor pairing baseline
-a-a-a-a unsigned long long
-a-a-a-a traditional_pack(
-a-a-a-a-a-a-a-a unsigned int x,
-a-a-a-a-a-a-a-a unsigned int y
-a-a-a-a ) {
-a-a-a-a-a-a-a-a unsigned long long sum = x + y;
-a-a-a-a-a-a-a-a return (sum * (sum + 1ULL)) / 2ULL + y;
-a-a-a-a }
-a-a-a-a // Traditional unsigned Cantor unpacker
-a-a-a-a cantor_pair
-a-a-a-a traditional_unpack(
-a-a-a-a-a-a-a-a unsigned long long w
-a-a-a-a ) {
-a-a-a-a-a-a-a-a unsigned long long t = static_cast<unsigned long
long>((std::sqrt(static_cast<double>(8ULL * w + 1ULL)) - 1.0) / 2.0);
-a-a-a-a-a-a-a-a unsigned long long tri = (t * (t + 1ULL)) / 2ULL;
-a-a-a-a-a-a-a-a unsigned long long Y = w - tri;
-a-a-a-a-a-a-a-a unsigned long long X = t - Y;
-a-a-a-a-a-a-a-a return { static_cast<int>(X), static_cast<int>(Y) };
-a-a-a-a }
-a-a-a-a // Pack two signed integers into a single unique natural number
(Moebius phase 1)
-a-a-a-a unsigned long long
-a-a-a-a pack_pair_signed(
-a-a-a-a-a-a-a-a int a,
-a-a-a-a-a-a-a-a int b
-a-a-a-a ) {
-a-a-a-a-a-a-a-a unsigned long long X = fold_z_to_n(a);
-a-a-a-a-a-a-a-a unsigned long long Y = fold_z_to_n(b);
-a-a-a-a-a-a-a-a unsigned long long sum = X + Y;
-a-a-a-a-a-a-a-a return (sum * (sum + 1ULL)) / 2ULL + Y;
-a-a-a-a }
-a-a-a-a // Unpack a single natural number back into a pair of signed
integers (Moebius phase 2)
-a-a-a-a cantor_pair unpack_seed_signed(
-a-a-a-a-a-a-a-a unsigned long long w
-a-a-a-a ) {
-a-a-a-a-a-a-a-a unsigned long long t = static_cast<unsigned long
long>((std::sqrt(static_cast<double>(8ULL * w + 1ULL)) - 1.0) / 2.0);
-a-a-a-a-a-a-a-a unsigned long long tri = (t * (t + 1ULL)) / 2ULL;
-a-a-a-a-a-a-a-a unsigned long long Y = w - tri;
-a-a-a-a-a-a-a-a unsigned long long X = t - Y;
-a-a-a-a-a-a-a-a return { unfold_n_to_z(X), unfold_n_to_z(Y) };
-a-a-a-a }
-a-a-a-a void
-a-a-a-a manifest()
-a-a-a-a {
-a-a-a-a-a-a-a-a std::cout << "ct_cantor_integer::manifest()\n";
-a-a-a-a-a-a-a-a // Testing purely positive inputs to allow comparison with >> traditional
-a-a-a-a-a-a-a-a int orig_a = 47;
-a-a-a-a-a-a-a-a int orig_b = 32;
-a-a-a-a-a-a-a-a std::cout << "-a Input Pair: (" << orig_a << ", " << orig_b <<
")\n\n";
-a-a-a-a-a-a-a-a //
=====================================================================
-a-a-a-a-a-a-a-a // TRADITIONAL UNSIGNED CANTOR PIPELINE
-a-a-a-a-a-a-a-a //
=====================================================================
-a-a-a-a-a-a-a-a unsigned long long trad_index = traditional_pack(orig_a, >> orig_b);
-a-a-a-a-a-a-a-a cantor_pair trad_recovered = traditional_unpack(trad_index);
-a-a-a-a-a-a-a-a std::cout << "-a === Traditional Unsigned Cantor ===\n";
-a-a-a-a-a-a-a-a std::cout << "-a-a-a Resulting Index:-a-a " << trad_index << "\n";
-a-a-a-a-a-a-a-a std::cout << "-a-a-a Unpacked Pair:-a-a-a-a (" << trad_recovered.m_a
<< ", " << trad_recovered.m_b << ")\n";
-a-a-a-a-a-a-a-a if (trad_recovered.m_a == orig_a && trad_recovered.m_b == >> orig_b) {
-a-a-a-a-a-a-a-a-a-a-a-a std::cout << "-a-a-a Verification:-a-a-a-a-a SUCCESS\n\n";
-a-a-a-a-a-a-a-a }
-a-a-a-a-a-a-a-a else {
-a-a-a-a-a-a-a-a-a-a-a-a std::cout << "-a-a-a Verification:-a-a-a-a-a FAILED\n\n";
-a-a-a-a-a-a-a-a }
-a-a-a-a-a-a-a-a //
=====================================================================
-a-a-a-a-a-a-a-a // MOEBIUS INTERLEAVED SIGNED PIPELINE
-a-a-a-a-a-a-a-a //
=====================================================================
-a-a-a-a-a-a-a-a unsigned long long moebius_nat_index = pack_pair_signed(orig_a,
orig_b);
-a-a-a-a-a-a-a-a int moebius_final_integer = unfold_n_to_z(moebius_nat_index);
-a-a-a-a-a-a-a-a // Reverse the mapping pipeline entirely
-a-a-a-a-a-a-a-a unsigned long long moebius_recovered_nat =
fold_z_to_n(moebius_final_integer);
-a-a-a-a-a-a-a-a cantor_pair moebius_recovered_pair =
unpack_seed_signed(moebius_recovered_nat);
-a-a-a-a-a-a-a-a std::cout << "-a === Moebius Interleaved Signed Cantor ===\n";
-a-a-a-a-a-a-a-a std::cout << "-a-a-a Intermediate Nat Index: " <<
moebius_nat_index << "\n";
-a-a-a-a-a-a-a-a std::cout << "-a-a-a Final Mapping (Z):-a-a-a-a-a-a " <<
moebius_final_integer << "\n";
-a-a-a-a-a-a-a-a std::cout << "-a-a-a Unpacked Pair:-a-a-a-a-a-a-a-a-a-a (" <<
moebius_recovered_pair.m_a << ", " << moebius_recovered_pair.m_b <<
")\n";
-a-a-a-a-a-a-a-a if (moebius_recovered_pair.m_a == orig_a &&
moebius_recovered_pair.m_b == orig_b) {
-a-a-a-a-a-a-a-a-a-a-a-a std::cout << "-a-a-a Verification:-a-a-a-a-a-a-a-a-a-a-a SUCCESS\n";
-a-a-a-a-a-a-a-a }
-a-a-a-a-a-a-a-a else {
-a-a-a-a-a-a-a-a-a-a-a-a std::cout << "-a-a-a Verification:-a-a-a-a-a-a-a-a-a-a-a FAILED\n";
-a-a-a-a-a-a-a-a }
-a-a-a-a }
}
________________________________
any thoughts? Thanks everybody! :^)
Why not typedef "unsigned long long" as "ull"?
Why not figure out what operator overloads would make sense as an arithmetization and then just use the plain syntax of arithmetic?
Why not bind a thread-local streams handle to make it so that
std::cout is not concrete for just plain "out"?
Why not make for something that's not static casts where it appears
that the use of static_cast loses precision or overflow?
Why not call this "Galileo pairing" since it was already around for
hundreds of years?
On 6/10/2026 8:55 AM, Ross Finlayson wrote:
On 06/09/2026 03:33 PM, Chris M. Thomasson wrote:
I tried to code up a quick and dirty way to use Cantor Pairing with
integers instead of just unsigned. Using a mapping from Moebius in a
different thread vs traditional unsigned Cantor.
Its funny... His mapping is giving me different numbers for when the
pair is two positive integers.
____________
ct_cantor_integer::manifest()
Input Pair: (47, 32)
=== Traditional Unsigned Cantor ===
Resulting Index: 3192
Unpacked Pair: (47, 32)
Verification: SUCCESS
=== Moebius Interleaved Signed Cantor ===
Intermediate Nat Index: 12625
Final Mapping (Z): -6313
Unpacked Pair: (47, 32)
Verification: SUCCESS
____________
Here is 3 and 4:
____________
ct_cantor_integer::manifest()
Input Pair: (3, 4)
=== Traditional Unsigned Cantor ===
Resulting Index: 32
Unpacked Pair: (3, 4)
Verification: SUCCESS
=== Moebius Interleaved Signed Cantor ===
Intermediate Nat Index: 113
Final Mapping (Z): -57
Unpacked Pair: (3, 4)
Verification: SUCCESS
____________
Okay, here is a run using a pair of (-11, 15)... Traditional Cantor
Pairing does not like that too much?
Oh it failed, but the integer map worked:
____________
ct_cantor_integer::manifest()
Input Pair: (-11, 15)
=== Traditional Unsigned Cantor ===
Resulting Index: 25
Unpacked Pair: (2, 4)
Verification: FAILED
=== Moebius Interleaved Signed Cantor ===
Intermediate Nat Index: 1356
Final Mapping (Z): 678
Unpacked Pair: (-11, 15)
Verification: SUCCESS
____________
Here is (42, 42), the both should work:
____________
ct_cantor_integer::manifest()
Input Pair: (42, 42)
=== Traditional Unsigned Cantor ===
Resulting Index: 3612
Unpacked Pair: (42, 42)
Verification: SUCCESS
=== Moebius Interleaved Signed Cantor ===
Intermediate Nat Index: 14280
Final Mapping (Z): 7140
Unpacked Pair: (42, 42)
Verification: SUCCESS
____________
Interesting!
Fwiw, here is my crude code:
________________________________
// For Moebius
// Quick and crude Cantor mapper.
// Works with integers, I think.
// When all the components are positive I can use
// traditional Cantor Pairing...
namespace ct_cantor_integer
{
struct cantor_pair
{
int m_a;
int m_b;
};
// Fold a signed integer Z into a natural number N
unsigned long long
fold_z_to_n(
int z
) {
if (z >= 0)
{
return 2ULL * static_cast<unsigned long long>(z);
}
else
{
long long positive_result = -2LL * static_cast<long
long>(z) - 1LL;
return static_cast<unsigned long long>(positive_result);
}
}
// Unfold a natural number N back into a signed integer Z
int
unfold_n_to_z(
unsigned long long n
) {
if (n % 2 == 0)
{
return static_cast<int>(n / 2ULL);
}
else
{
return static_cast<int>(-static_cast<long long>((n + 1ULL)
/ 2ULL));
}
}
// Pure, traditional unsigned Cantor pairing baseline
unsigned long long
traditional_pack(
unsigned int x,
unsigned int y
) {
unsigned long long sum = x + y;
return (sum * (sum + 1ULL)) / 2ULL + y;
}
// Traditional unsigned Cantor unpacker
cantor_pair
traditional_unpack(
unsigned long long w
) {
unsigned long long t = static_cast<unsigned long
long>((std::sqrt(static_cast<double>(8ULL * w + 1ULL)) - 1.0) / 2.0);
unsigned long long tri = (t * (t + 1ULL)) / 2ULL;
unsigned long long Y = w - tri;
unsigned long long X = t - Y;
return { static_cast<int>(X), static_cast<int>(Y) };
}
// Pack two signed integers into a single unique natural number
(Moebius phase 1)
unsigned long long
pack_pair_signed(
int a,
int b
) {
unsigned long long X = fold_z_to_n(a);
unsigned long long Y = fold_z_to_n(b);
unsigned long long sum = X + Y;
return (sum * (sum + 1ULL)) / 2ULL + Y;
}
// Unpack a single natural number back into a pair of signed
integers (Moebius phase 2)
cantor_pair unpack_seed_signed(
unsigned long long w
) {
unsigned long long t = static_cast<unsigned long
long>((std::sqrt(static_cast<double>(8ULL * w + 1ULL)) - 1.0) / 2.0);
unsigned long long tri = (t * (t + 1ULL)) / 2ULL;
unsigned long long Y = w - tri;
unsigned long long X = t - Y;
return { unfold_n_to_z(X), unfold_n_to_z(Y) };
}
void
manifest()
{
std::cout << "ct_cantor_integer::manifest()\n";
// Testing purely positive inputs to allow comparison with
traditional
int orig_a = 47;
int orig_b = 32;
std::cout << " Input Pair: (" << orig_a << ", " << orig_b <<
")\n\n";
//
=====================================================================
// TRADITIONAL UNSIGNED CANTOR PIPELINE
//
=====================================================================
unsigned long long trad_index = traditional_pack(orig_a,
orig_b);
cantor_pair trad_recovered = traditional_unpack(trad_index);
std::cout << " === Traditional Unsigned Cantor ===\n";
std::cout << " Resulting Index: " << trad_index << "\n";
std::cout << " Unpacked Pair: (" << trad_recovered.m_a
<< ", " << trad_recovered.m_b << ")\n";
if (trad_recovered.m_a == orig_a && trad_recovered.m_b ==
orig_b) {
std::cout << " Verification: SUCCESS\n\n";
}
else {
std::cout << " Verification: FAILED\n\n";
}
//
=====================================================================
// MOEBIUS INTERLEAVED SIGNED PIPELINE
//
=====================================================================
unsigned long long moebius_nat_index = pack_pair_signed(orig_a, >>> orig_b);
int moebius_final_integer = unfold_n_to_z(moebius_nat_index);
// Reverse the mapping pipeline entirely
unsigned long long moebius_recovered_nat =
fold_z_to_n(moebius_final_integer);
cantor_pair moebius_recovered_pair =
unpack_seed_signed(moebius_recovered_nat);
std::cout << " === Moebius Interleaved Signed Cantor ===\n";
std::cout << " Intermediate Nat Index: " <<
moebius_nat_index << "\n";
std::cout << " Final Mapping (Z): " <<
moebius_final_integer << "\n";
std::cout << " Unpacked Pair: (" <<
moebius_recovered_pair.m_a << ", " << moebius_recovered_pair.m_b <<
")\n";
if (moebius_recovered_pair.m_a == orig_a &&
moebius_recovered_pair.m_b == orig_b) {
std::cout << " Verification: SUCCESS\n";
}
else {
std::cout << " Verification: FAILED\n";
}
}
}
________________________________
any thoughts? Thanks everybody! :^)
Why not typedef "unsigned long long" as "ull"?
Because that is moronic...
Why not figure out what operator overloads would make sense as an
arithmetization and then just use the plain syntax of arithmetic?
Why not bind a thread-local streams handle to make it so that
std::cout is not concrete for just plain "out"?
Yuh? Have you ever used C++ before?
Why not make for something that's not static casts where it appears
that the use of static_cast loses precision or overflow?
This quick code is not meant to be arbitrary precision.
Why not call this "Galileo pairing" since it was already around for
hundreds of years?
The Cantor Pairing aspect? Or the mapping from Moebius?
On 06/15/2026 03:14 PM, Chris M. Thomasson wrote:
On 6/10/2026 8:55 AM, Ross Finlayson wrote:
On 06/09/2026 03:33 PM, Chris M. Thomasson wrote:
I tried to code up a quick and dirty way to use Cantor Pairing with
integers instead of just unsigned. Using a mapping from Moebius in a
different thread vs traditional unsigned Cantor.
Its funny... His mapping is giving me different numbers for when the
pair is two positive integers.
____________
ct_cantor_integer::manifest()
-a-a Input Pair: (47, 32)
-a-a === Traditional Unsigned Cantor ===
-a-a-a-a Resulting Index:-a-a 3192
-a-a-a-a Unpacked Pair:-a-a-a-a (47, 32)
-a-a-a-a Verification:-a-a-a-a-a SUCCESS
-a-a === Moebius Interleaved Signed Cantor ===
-a-a-a-a Intermediate Nat Index: 12625
-a-a-a-a Final Mapping (Z):-a-a-a-a-a-a -6313
-a-a-a-a Unpacked Pair:-a-a-a-a-a-a-a-a-a-a (47, 32)
-a-a-a-a Verification:-a-a-a-a-a-a-a-a-a-a-a SUCCESS
____________
Here is 3 and 4:
____________
ct_cantor_integer::manifest()
-a-a Input Pair: (3, 4)
-a-a === Traditional Unsigned Cantor ===
-a-a-a-a Resulting Index:-a-a 32
-a-a-a-a Unpacked Pair:-a-a-a-a (3, 4)
-a-a-a-a Verification:-a-a-a-a-a SUCCESS
-a-a === Moebius Interleaved Signed Cantor ===
-a-a-a-a Intermediate Nat Index: 113
-a-a-a-a Final Mapping (Z):-a-a-a-a-a-a -57
-a-a-a-a Unpacked Pair:-a-a-a-a-a-a-a-a-a-a (3, 4)
-a-a-a-a Verification:-a-a-a-a-a-a-a-a-a-a-a SUCCESS
____________
Okay, here is a run using a pair of (-11, 15)... Traditional Cantor
Pairing does not like that too much?
Oh it failed, but the integer map worked:
____________
ct_cantor_integer::manifest()
-a-a Input Pair: (-11, 15)
-a-a === Traditional Unsigned Cantor ===
-a-a-a-a Resulting Index:-a-a 25
-a-a-a-a Unpacked Pair:-a-a-a-a (2, 4)
-a-a-a-a Verification:-a-a-a-a-a FAILED
-a-a === Moebius Interleaved Signed Cantor ===
-a-a-a-a Intermediate Nat Index: 1356
-a-a-a-a Final Mapping (Z):-a-a-a-a-a-a 678
-a-a-a-a Unpacked Pair:-a-a-a-a-a-a-a-a-a-a (-11, 15)
-a-a-a-a Verification:-a-a-a-a-a-a-a-a-a-a-a SUCCESS
____________
Here is (42, 42), the both should work:
____________
ct_cantor_integer::manifest()
-a-a Input Pair: (42, 42)
-a-a === Traditional Unsigned Cantor ===
-a-a-a-a Resulting Index:-a-a 3612
-a-a-a-a Unpacked Pair:-a-a-a-a (42, 42)
-a-a-a-a Verification:-a-a-a-a-a SUCCESS
-a-a === Moebius Interleaved Signed Cantor ===
-a-a-a-a Intermediate Nat Index: 14280
-a-a-a-a Final Mapping (Z):-a-a-a-a-a-a 7140
-a-a-a-a Unpacked Pair:-a-a-a-a-a-a-a-a-a-a (42, 42)
-a-a-a-a Verification:-a-a-a-a-a-a-a-a-a-a-a SUCCESS
____________
Interesting!
Fwiw, here is my crude code:
________________________________
// For Moebius
// Quick and crude Cantor mapper.
// Works with integers, I think.
// When all the components are positive I can use
// traditional Cantor Pairing...
namespace ct_cantor_integer
{
-a-a-a-a struct cantor_pair
-a-a-a-a {
-a-a-a-a-a-a-a-a int m_a;
-a-a-a-a-a-a-a-a int m_b;
-a-a-a-a };
-a-a-a-a // Fold a signed integer Z into a natural number N
-a-a-a-a unsigned long long
-a-a-a-a fold_z_to_n(
-a-a-a-a-a-a-a-a int z
-a-a-a-a ) {
-a-a-a-a-a-a-a-a if (z >= 0)
-a-a-a-a-a-a-a-a {
-a-a-a-a-a-a-a-a-a-a-a-a return 2ULL * static_cast<unsigned long long>(z); >>>> -a-a-a-a-a-a-a-a }
-a-a-a-a-a-a-a-a else
-a-a-a-a-a-a-a-a {
-a-a-a-a-a-a-a-a-a-a-a-a long long positive_result = -2LL * static_cast<long
long>(z) - 1LL;
-a-a-a-a-a-a-a-a-a-a-a-a return static_cast<unsigned long long>(positive_result);
-a-a-a-a-a-a-a-a }
-a-a-a-a }
-a-a-a-a // Unfold a natural number N back into a signed integer Z
-a-a-a-a int
-a-a-a-a unfold_n_to_z(
-a-a-a-a-a-a-a-a unsigned long long n
-a-a-a-a ) {
-a-a-a-a-a-a-a-a if (n % 2 == 0)
-a-a-a-a-a-a-a-a {
-a-a-a-a-a-a-a-a-a-a-a-a return static_cast<int>(n / 2ULL);
-a-a-a-a-a-a-a-a }
-a-a-a-a-a-a-a-a else
-a-a-a-a-a-a-a-a {
-a-a-a-a-a-a-a-a-a-a-a-a return static_cast<int>(-static_cast<long long>((n + 1ULL)
/ 2ULL));
-a-a-a-a-a-a-a-a }
-a-a-a-a }
-a-a-a-a // Pure, traditional unsigned Cantor pairing baseline
-a-a-a-a unsigned long long
-a-a-a-a traditional_pack(
-a-a-a-a-a-a-a-a unsigned int x,
-a-a-a-a-a-a-a-a unsigned int y
-a-a-a-a ) {
-a-a-a-a-a-a-a-a unsigned long long sum = x + y;
-a-a-a-a-a-a-a-a return (sum * (sum + 1ULL)) / 2ULL + y;
-a-a-a-a }
-a-a-a-a // Traditional unsigned Cantor unpacker
-a-a-a-a cantor_pair
-a-a-a-a traditional_unpack(
-a-a-a-a-a-a-a-a unsigned long long w
-a-a-a-a ) {
-a-a-a-a-a-a-a-a unsigned long long t = static_cast<unsigned long
long>((std::sqrt(static_cast<double>(8ULL * w + 1ULL)) - 1.0) / 2.0);
-a-a-a-a-a-a-a-a unsigned long long tri = (t * (t + 1ULL)) / 2ULL;
-a-a-a-a-a-a-a-a unsigned long long Y = w - tri;
-a-a-a-a-a-a-a-a unsigned long long X = t - Y;
-a-a-a-a-a-a-a-a return { static_cast<int>(X), static_cast<int>(Y) };
-a-a-a-a }
-a-a-a-a // Pack two signed integers into a single unique natural number >>>> (Moebius phase 1)
-a-a-a-a unsigned long long
-a-a-a-a pack_pair_signed(
-a-a-a-a-a-a-a-a int a,
-a-a-a-a-a-a-a-a int b
-a-a-a-a ) {
-a-a-a-a-a-a-a-a unsigned long long X = fold_z_to_n(a);
-a-a-a-a-a-a-a-a unsigned long long Y = fold_z_to_n(b);
-a-a-a-a-a-a-a-a unsigned long long sum = X + Y;
-a-a-a-a-a-a-a-a return (sum * (sum + 1ULL)) / 2ULL + Y;
-a-a-a-a }
-a-a-a-a // Unpack a single natural number back into a pair of signed
integers (Moebius phase 2)
-a-a-a-a cantor_pair unpack_seed_signed(
-a-a-a-a-a-a-a-a unsigned long long w
-a-a-a-a ) {
-a-a-a-a-a-a-a-a unsigned long long t = static_cast<unsigned long
long>((std::sqrt(static_cast<double>(8ULL * w + 1ULL)) - 1.0) / 2.0);
-a-a-a-a-a-a-a-a unsigned long long tri = (t * (t + 1ULL)) / 2ULL;
-a-a-a-a-a-a-a-a unsigned long long Y = w - tri;
-a-a-a-a-a-a-a-a unsigned long long X = t - Y;
-a-a-a-a-a-a-a-a return { unfold_n_to_z(X), unfold_n_to_z(Y) };
-a-a-a-a }
-a-a-a-a void
-a-a-a-a manifest()
-a-a-a-a {
-a-a-a-a-a-a-a-a std::cout << "ct_cantor_integer::manifest()\n";
-a-a-a-a-a-a-a-a // Testing purely positive inputs to allow comparison with
traditional
-a-a-a-a-a-a-a-a int orig_a = 47;
-a-a-a-a-a-a-a-a int orig_b = 32;
-a-a-a-a-a-a-a-a std::cout << "-a Input Pair: (" << orig_a << ", " << orig_b <<
")\n\n";
-a-a-a-a-a-a-a-a //
=====================================================================
-a-a-a-a-a-a-a-a // TRADITIONAL UNSIGNED CANTOR PIPELINE
-a-a-a-a-a-a-a-a //
=====================================================================
-a-a-a-a-a-a-a-a unsigned long long trad_index = traditional_pack(orig_a, >>>> orig_b);
-a-a-a-a-a-a-a-a cantor_pair trad_recovered = traditional_unpack(trad_index);
-a-a-a-a-a-a-a-a std::cout << "-a === Traditional Unsigned Cantor ===\n"; >>>> -a-a-a-a-a-a-a-a std::cout << "-a-a-a Resulting Index:-a-a " << trad_index << "\n";
-a-a-a-a-a-a-a-a std::cout << "-a-a-a Unpacked Pair:-a-a-a-a (" << trad_recovered.m_a
<< ", " << trad_recovered.m_b << ")\n";
-a-a-a-a-a-a-a-a if (trad_recovered.m_a == orig_a && trad_recovered.m_b == >>>> orig_b) {
-a-a-a-a-a-a-a-a-a-a-a-a std::cout << "-a-a-a Verification:-a-a-a-a-a SUCCESS\n\n";
-a-a-a-a-a-a-a-a }
-a-a-a-a-a-a-a-a else {
-a-a-a-a-a-a-a-a-a-a-a-a std::cout << "-a-a-a Verification:-a-a-a-a-a FAILED\n\n";
-a-a-a-a-a-a-a-a }
-a-a-a-a-a-a-a-a //
=====================================================================
-a-a-a-a-a-a-a-a // MOEBIUS INTERLEAVED SIGNED PIPELINE
-a-a-a-a-a-a-a-a //
=====================================================================
-a-a-a-a-a-a-a-a unsigned long long moebius_nat_index =
pack_pair_signed(orig_a,
orig_b);
-a-a-a-a-a-a-a-a int moebius_final_integer = unfold_n_to_z(moebius_nat_index);
-a-a-a-a-a-a-a-a // Reverse the mapping pipeline entirely
-a-a-a-a-a-a-a-a unsigned long long moebius_recovered_nat =
fold_z_to_n(moebius_final_integer);
-a-a-a-a-a-a-a-a cantor_pair moebius_recovered_pair =
unpack_seed_signed(moebius_recovered_nat);
-a-a-a-a-a-a-a-a std::cout << "-a === Moebius Interleaved Signed Cantor ===\n";
-a-a-a-a-a-a-a-a std::cout << "-a-a-a Intermediate Nat Index: " <<
moebius_nat_index << "\n";
-a-a-a-a-a-a-a-a std::cout << "-a-a-a Final Mapping (Z):-a-a-a-a-a-a " << >>>> moebius_final_integer << "\n";
-a-a-a-a-a-a-a-a std::cout << "-a-a-a Unpacked Pair:-a-a-a-a-a-a-a-a-a-a (" <<
moebius_recovered_pair.m_a << ", " << moebius_recovered_pair.m_b <<
")\n";
-a-a-a-a-a-a-a-a if (moebius_recovered_pair.m_a == orig_a &&
moebius_recovered_pair.m_b == orig_b) {
-a-a-a-a-a-a-a-a-a-a-a-a std::cout << "-a-a-a Verification:-a-a-a-a-a-a-a-a-a-a-a SUCCESS\n";
-a-a-a-a-a-a-a-a }
-a-a-a-a-a-a-a-a else {
-a-a-a-a-a-a-a-a-a-a-a-a std::cout << "-a-a-a Verification:-a-a-a-a-a-a-a-a-a-a-a FAILED\n";
-a-a-a-a-a-a-a-a }
-a-a-a-a }
}
________________________________
any thoughts? Thanks everybody! :^)
Why not typedef "unsigned long long" as "ull"?
Because that is moronic...
Why not figure out what operator overloads would make sense as an
arithmetization and then just use the plain syntax of arithmetic?
Why not bind a thread-local streams handle to make it so that
std::cout is not concrete for just plain "out"?
Yuh? Have you ever used C++ before?
Why not make for something that's not static casts where it appears
that the use of static_cast loses precision or overflow?
This quick code is not meant to be arbitrary precision.
Why not call this "Galileo pairing" since it was already around for
hundreds of years?
The Cantor Pairing aspect? Or the mapping from Moebius?
Heh, have I ever programmed in C++ before.
You know, really it was always "C/C++".
I suppose though Java's my main yet after a while all languages look the same.
These days it's "typed templating assembler", sort of the idea.
Have I written about half a million lines of code?
That's only 50 KLOC's, ....
One good file is 2.5, ..., takes about a month, 12 x 20 = 240,
by 2.5, about 600, KLOC's. Some years are better than others.
Yeah, I know, these days I write adapters to anything,
I just can't stand concrete worlders any more.
The "typing and templating assembler", though, sort of a retro kick,
though it seems to make sense to surface the machine.
Why "out" is because "in".
Yeah, I've "used C++ before".
On 6/15/2026 8:56 PM, Ross Finlayson wrote:
On 06/15/2026 03:14 PM, Chris M. Thomasson wrote:
On 6/10/2026 8:55 AM, Ross Finlayson wrote:
On 06/09/2026 03:33 PM, Chris M. Thomasson wrote:
I tried to code up a quick and dirty way to use Cantor Pairing with
integers instead of just unsigned. Using a mapping from Moebius in a >>>>> different thread vs traditional unsigned Cantor.
Its funny... His mapping is giving me different numbers for when the >>>>> pair is two positive integers.
____________
ct_cantor_integer::manifest()
Input Pair: (47, 32)
=== Traditional Unsigned Cantor ===
Resulting Index: 3192
Unpacked Pair: (47, 32)
Verification: SUCCESS
=== Moebius Interleaved Signed Cantor ===
Intermediate Nat Index: 12625
Final Mapping (Z): -6313
Unpacked Pair: (47, 32)
Verification: SUCCESS
____________
Here is 3 and 4:
____________
ct_cantor_integer::manifest()
Input Pair: (3, 4)
=== Traditional Unsigned Cantor ===
Resulting Index: 32
Unpacked Pair: (3, 4)
Verification: SUCCESS
=== Moebius Interleaved Signed Cantor ===
Intermediate Nat Index: 113
Final Mapping (Z): -57
Unpacked Pair: (3, 4)
Verification: SUCCESS
____________
Okay, here is a run using a pair of (-11, 15)... Traditional Cantor
Pairing does not like that too much?
Oh it failed, but the integer map worked:
____________
ct_cantor_integer::manifest()
Input Pair: (-11, 15)
=== Traditional Unsigned Cantor ===
Resulting Index: 25
Unpacked Pair: (2, 4)
Verification: FAILED
=== Moebius Interleaved Signed Cantor ===
Intermediate Nat Index: 1356
Final Mapping (Z): 678
Unpacked Pair: (-11, 15)
Verification: SUCCESS
____________
Here is (42, 42), the both should work:
____________
ct_cantor_integer::manifest()
Input Pair: (42, 42)
=== Traditional Unsigned Cantor ===
Resulting Index: 3612
Unpacked Pair: (42, 42)
Verification: SUCCESS
=== Moebius Interleaved Signed Cantor ===
Intermediate Nat Index: 14280
Final Mapping (Z): 7140
Unpacked Pair: (42, 42)
Verification: SUCCESS
____________
Interesting!
Fwiw, here is my crude code:
________________________________
// For Moebius
// Quick and crude Cantor mapper.
// Works with integers, I think.
// When all the components are positive I can use
// traditional Cantor Pairing...
namespace ct_cantor_integer
{
struct cantor_pair
{
int m_a;
int m_b;
};
// Fold a signed integer Z into a natural number N
unsigned long long
fold_z_to_n(
int z
) {
if (z >= 0)
{
return 2ULL * static_cast<unsigned long long>(z);
}
else
{
long long positive_result = -2LL * static_cast<long
long>(z) - 1LL;
return static_cast<unsigned long long>(positive_result); >>>>> }
}
// Unfold a natural number N back into a signed integer Z
int
unfold_n_to_z(
unsigned long long n
) {
if (n % 2 == 0)
{
return static_cast<int>(n / 2ULL);
}
else
{
return static_cast<int>(-static_cast<long long>((n +
1ULL)
/ 2ULL));
}
}
// Pure, traditional unsigned Cantor pairing baseline
unsigned long long
traditional_pack(
unsigned int x,
unsigned int y
) {
unsigned long long sum = x + y;
return (sum * (sum + 1ULL)) / 2ULL + y;
}
// Traditional unsigned Cantor unpacker
cantor_pair
traditional_unpack(
unsigned long long w
) {
unsigned long long t = static_cast<unsigned long
long>((std::sqrt(static_cast<double>(8ULL * w + 1ULL)) - 1.0) / 2.0); >>>>> unsigned long long tri = (t * (t + 1ULL)) / 2ULL;
unsigned long long Y = w - tri;
unsigned long long X = t - Y;
return { static_cast<int>(X), static_cast<int>(Y) };
}
// Pack two signed integers into a single unique natural number >>>>> (Moebius phase 1)
unsigned long long
pack_pair_signed(
int a,
int b
) {
unsigned long long X = fold_z_to_n(a);
unsigned long long Y = fold_z_to_n(b);
unsigned long long sum = X + Y;
return (sum * (sum + 1ULL)) / 2ULL + Y;
}
// Unpack a single natural number back into a pair of signed
integers (Moebius phase 2)
cantor_pair unpack_seed_signed(
unsigned long long w
) {
unsigned long long t = static_cast<unsigned long
long>((std::sqrt(static_cast<double>(8ULL * w + 1ULL)) - 1.0) / 2.0); >>>>> unsigned long long tri = (t * (t + 1ULL)) / 2ULL;
unsigned long long Y = w - tri;
unsigned long long X = t - Y;
return { unfold_n_to_z(X), unfold_n_to_z(Y) };
}
void
manifest()
{
std::cout << "ct_cantor_integer::manifest()\n";
// Testing purely positive inputs to allow comparison with
traditional
int orig_a = 47;
int orig_b = 32;
std::cout << " Input Pair: (" << orig_a << ", " << orig_b << >>>>> ")\n\n";
//
===================================================================== >>>>> // TRADITIONAL UNSIGNED CANTOR PIPELINE
//
===================================================================== >>>>> unsigned long long trad_index = traditional_pack(orig_a,
orig_b);
cantor_pair trad_recovered = traditional_unpack(trad_index); >>>>>
std::cout << " === Traditional Unsigned Cantor ===\n";
std::cout << " Resulting Index: " << trad_index << "\n"; >>>>> std::cout << " Unpacked Pair: (" << trad_recovered.m_a >>>>> << ", " << trad_recovered.m_b << ")\n";
if (trad_recovered.m_a == orig_a && trad_recovered.m_b ==
orig_b) {
std::cout << " Verification: SUCCESS\n\n";
}
else {
std::cout << " Verification: FAILED\n\n";
}
//
===================================================================== >>>>> // MOEBIUS INTERLEAVED SIGNED PIPELINE
//
===================================================================== >>>>> unsigned long long moebius_nat_index =
pack_pair_signed(orig_a,
orig_b);
int moebius_final_integer = unfold_n_to_z(moebius_nat_index); >>>>>
// Reverse the mapping pipeline entirely
unsigned long long moebius_recovered_nat =
fold_z_to_n(moebius_final_integer);
cantor_pair moebius_recovered_pair =
unpack_seed_signed(moebius_recovered_nat);
std::cout << " === Moebius Interleaved Signed Cantor ===\n"; >>>>> std::cout << " Intermediate Nat Index: " <<
moebius_nat_index << "\n";
std::cout << " Final Mapping (Z): " <<
moebius_final_integer << "\n";
std::cout << " Unpacked Pair: (" <<
moebius_recovered_pair.m_a << ", " << moebius_recovered_pair.m_b <<
")\n";
if (moebius_recovered_pair.m_a == orig_a &&
moebius_recovered_pair.m_b == orig_b) {
std::cout << " Verification: SUCCESS\n";
}
else {
std::cout << " Verification: FAILED\n";
}
}
}
________________________________
any thoughts? Thanks everybody! :^)
Why not typedef "unsigned long long" as "ull"?
Because that is moronic...
Why not figure out what operator overloads would make sense as an
arithmetization and then just use the plain syntax of arithmetic?
Why not bind a thread-local streams handle to make it so that
std::cout is not concrete for just plain "out"?
Yuh? Have you ever used C++ before?
Why not make for something that's not static casts where it appears
that the use of static_cast loses precision or overflow?
This quick code is not meant to be arbitrary precision.
Why not call this "Galileo pairing" since it was already around for
hundreds of years?
The Cantor Pairing aspect? Or the mapping from Moebius?
Heh, have I ever programmed in C++ before.
You know, really it was always "C/C++".
Huh? C and C++ are different langs. But you know that right?
I suppose though Java's my main yet after a while all languages look the
same.
These days it's "typed templating assembler", sort of the idea.
assembler? Oh yeah I am familiar with that. Wrote a lot of ASM code for
the x86/x64, SPARC, some PPC. Fwiw, the wayback machine still has some
of my old code:
https://web.archive.org/web/20060214112345/http://appcore.home.comcast.net/appcore/src/cpu/i686/ac_i686_gcc_asm.html
Have I written about half a million lines of code?
I have written a shit load of code.
That's only 50 KLOC's, ....
One good file is 2.5, ..., takes about a month, 12 x 20 = 240,
by 2.5, about 600, KLOC's. Some years are better than others.
Yeah, I know, these days I write adapters to anything,
I just can't stand concrete worlders any more.
The "typing and templating assembler", though, sort of a retro kick,
though it seems to make sense to surface the machine.
Retro? ASM is modern. I had to use it for a bunch of lock/wait free algorithms before C++11 or C11.
Why "out" is because "in".
Yeah, I've "used C++ before".
Why in the world would you typedef such a thing!
"Why not typedef "unsigned long long" as "ull"?"
Oh you are canned!
Fwiw, here is some of my old ASM code, AT&T syntax:
# Copyright 2005 Chris Thomasson
.align 16
.globl np_ac_i686_atomic_dwcas_fence
np_ac_i686_atomic_dwcas_fence:
pushl %esi
pushl %ebx
movl 16(%esp), %esi
movl (%esi), %eax
movl 4(%esi), %edx
movl 20(%esp), %esi
movl (%esi), %ebx
movl 4(%esi), %ecx
movl 12(%esp), %esi
lock cmpxchg8b (%esi)
jne np_ac_i686_atomic_dwcas_fence_fail
xorl %eax, %eax
popl %ebx
popl %esi
ret
np_ac_i686_atomic_dwcas_fence_fail:
movl 16(%esp), %esi
movl %eax, (%esi)
movl %edx, 4(%esi)
movl $1, %eax
popl %ebx
popl %esi
ret
.align 16
.globl ac_i686_stack_mpmc_push_cas
ac_i686_stack_mpmc_push_cas:
movl 4(%esp), %edx
movl (%edx), %eax
movl 8(%esp), %ecx
ac_i686_stack_mpmc_push_cas_retry:
movl %eax, (%ecx)
lock cmpxchgl %ecx, (%edx)
jne ac_i686_stack_mpmc_push_cas_retry
ret
.align 16
.globl np_ac_i686_lfgc_smr_stack_mpmc_pop_dwcas np_ac_i686_lfgc_smr_stack_mpmc_pop_dwcas:
pushl %esi
pushl %ebx
np_ac_i686_lfgc_smr_stack_mpmc_pop_dwcas_reload:
movl 12(%esp), %esi
movl 4(%esi), %edx
movl (%esi), %eax
np_ac_i686_lfgc_smr_stack_mpmc_pop_dwcas_retry:
movl 16(%esp), %ebx
movl %eax, (%ebx)
mfence
cmpl (%esi), %eax
jne np_ac_i686_lfgc_smr_stack_mpmc_pop_dwcas_reload
test %eax, %eax
je np_ac_i686_lfgc_smr_stack_mpmc_pop_dwcas_fail
movl (%eax), %ebx
leal 1(%edx), %ecx
lock cmpxchg8b (%esi)
jne np_ac_i686_lfgc_smr_stack_mpmc_pop_dwcas_retry
np_ac_i686_lfgc_smr_stack_mpmc_pop_dwcas_fail:
movl 16(%esp), %esi
xorl %ebx, %ebx
movl %ebx, (%esi)
popl %ebx
popl %esi
ret
.align 16
.globl np_ac_i686_stack_mpmc_pop_dwcas
np_ac_i686_stack_mpmc_pop_dwcas:
pushl %esi
pushl %ebx
movl 12(%esp), %esi
movl 4(%esi), %edx
movl (%esi), %eax
np_ac_i686_stack_mpmc_pop_dwcas_retry:
test %eax, %eax
je np_ac_i686_stack_mpmc_pop_dwcas_fail
movl (%eax), %ebx
leal 1(%edx), %ecx
lock cmpxchg8b (%esi)
jne np_ac_i686_stack_mpmc_pop_dwcas_retry
np_ac_i686_stack_mpmc_pop_dwcas_fail:
popl %ebx
popl %esi
ret
.align 16
.globl ac_i686_lfgc_smr_activate
ac_i686_lfgc_smr_activate:
movl 4(%esp), %edx
movl 8(%esp), %ecx
ac_i686_lfgc_smr_activate_reload:
movl (%ecx), %eax
movl %eax, (%edx)
mfence
cmpl (%ecx), %eax
jne ac_i686_lfgc_smr_activate_reload
ret
.align 16
.globl ac_i686_lfgc_smr_deactivate
ac_i686_lfgc_smr_deactivate:
movl 4(%esp), %ecx
xorl %eax, %eax
movl %eax, (%ecx)
ret
.align 16
.globl ac_i686_queue_spsc_push
ac_i686_queue_spsc_push:
movl 4(%esp), %eax
movl 8(%esp), %ecx
movl 4(%eax), %edx
# sfence may be needed here for future x86
movl %ecx, (%edx)
movl %ecx, 4(%eax)
ret
.align 16
.globl ac_i686_queue_spsc_pop
ac_i686_queue_spsc_pop:
pushl %ebx
movl 8(%esp), %ecx
movl (%ecx), %eax
cmpl 4(%ecx), %eax
je ac_i686_queue_spsc_pop_failed
movl (%eax), %edx
# lfence may be needed here for future x86
movl 12(%edx), %ebx
movl %edx, (%ecx)
movl %ebx, 12(%eax)
popl %ebx
ret
ac_i686_queue_spsc_pop_failed:
xorl %eax, %eax
popl %ebx
ret
.align 16
.globl ac_i686_mb_fence
ac_i686_mb_fence:
mfence
ret
.align 16
.globl ac_i686_mb_naked
ac_i686_mb_naked:
ret
.align 16
.globl ac_i686_mb_store_fence
ac_i686_mb_store_fence:
movl 4(%esp), %ecx
movl 8(%esp), %eax
mfence
movl %eax, (%ecx)
ret
.align 16
.globl ac_i686_mb_store_naked
ac_i686_mb_store_naked:
movl 4(%esp), %ecx
movl 8(%esp), %eax
movl %eax, (%ecx)
ret
.align 16
.globl ac_i686_mb_load_fence
ac_i686_mb_load_fence:
movl 4(%esp), %ecx
movl (%ecx), %eax
mfence
ret
.align 16
.globl ac_i686_mb_load_naked
ac_i686_mb_load_naked:
movl 4(%esp), %ecx
movl (%ecx), %eax
ret
.align 16
.globl ac_i686_atomic_xchg_fence
ac_i686_atomic_xchg_fence:
movl 4(%esp), %ecx
movl 8(%esp), %eax
xchgl %eax, (%ecx)
ret
.align 16
.globl ac_i686_atomic_xadd_fence
ac_i686_atomic_xadd_fence:
movl 4(%esp), %ecx
movl 8(%esp), %eax
lock xaddl %eax, (%ecx)
ret
.align 16
.globl ac_i686_atomic_inc_fence
ac_i686_atomic_inc_fence:
movl 4(%esp), %ecx
movl $1, %eax
lock xaddl %eax, (%ecx)
incl %eax
ret
.align 16
.globl ac_i686_atomic_dec_fence
ac_i686_atomic_dec_fence:
movl 4(%esp), %ecx
movl $-1, %eax
lock xaddl %eax, (%ecx)
decl %eax
ret
.align 16
.globl ac_i686_atomic_cas_fence
ac_i686_atomic_cas_fence:
movl 4(%esp), %ecx
movl 8(%esp), %eax
movl 12(%esp), %edx
lock cmpxchgl %edx, (%ecx)
ret
On 6/17/2026 7:47 AM, Ross Finlayson wrote:
[...]
RossrCa I appreciate the enthusiasm, but IrCOve actually written and shipped some of my lockrCafree algorithms in real assembly on x86, SPARC, and PPC. The rest lived in research branches or internal tooling, but the point stands: the code I posted reflects hardware constraints, not stylistic preferences.
Your suggestions... typedefs (ull?, puke), operator overloads,
threadrCalocal streams donrCOt apply to atomic primitives or reversible integer mappings. These arenrCOt aesthetic problems; theyrCOre mathematical and architectural ones.
If you want to talk Cantor pairing or signed bijections, great.
If you want to talk atomic semantics or memory ordering, also great.
But the critique needs to match the domain.
And typedefrCOing unsigned long long into oblivion?
ThatrCOs the kind of thing that gets codebases rCo not people rCo fired.
Show me some of your old code.
Thank God the Wayback Machine still has some of mine:
https://web.archive.org/web/20060214112345/http://appcore.home.comcast.net/appcore/src/cpu/i686/ac_i686_gcc_asm.html
ThreadrCalocal streams? Interesting idea in the abstract. Writing into a perrCathread buffer is fine. but it has nothing to do with atomic RMW instructions or Cantor mappings. I created a little program to help me
port some of my algorithms to AppleSoft BASIC of all things. Shit man,
look up the thread Macro Issue by me over on comp.lang.c++
On 06/17/2026 08:48 PM, Chris M. Thomasson wrote:
On 6/17/2026 7:47 AM, Ross Finlayson wrote:
[...]
RossrCa I appreciate the enthusiasm, but IrCOve actually written and shipped >> some of my lockrCafree algorithms in real assembly on x86, SPARC, and PPC. >> The rest lived in research branches or internal tooling, but the point
stands: the code I posted reflects hardware constraints, not stylistic
preferences.
Your suggestions... typedefs (ull?, puke), operator overloads,
threadrCalocal streams donrCOt apply to atomic primitives or reversible
integer mappings. These arenrCOt aesthetic problems; theyrCOre mathematical >> and architectural ones.
If you want to talk Cantor pairing or signed bijections, great.
If you want to talk atomic semantics or memory ordering, also great.
But the critique needs to match the domain.
And typedefrCOing unsigned long long into oblivion?
ThatrCOs the kind of thing that gets codebases rCo not people rCo fired.
Show me some of your old code.
Thank God the Wayback Machine still has some of mine:
https://web.archive.org/web/20060214112345/http://appcore.home.comcast.net/appcore/src/cpu/i686/ac_i686_gcc_asm.html
ThreadrCalocal streams? Interesting idea in the abstract. Writing into a
perrCathread buffer is fine. but it has nothing to do with atomic RMW
instructions or Cantor mappings. I created a little program to help me
port some of my algorithms to AppleSoft BASIC of all things. Shit man,
look up the thread Macro Issue by me over on comp.lang.c++
Hm. Most of the code I've written was for work, I don't keep any copies
of work code, since, it's intellectual property of others.
Unless they've re-written it since Windows 7, I suppose some few lines
of code I wrote run every time Windows boots. There's tiff2pdf.c,
that was a long time ago, it's installed in millions of machines,
and does work all the time.
I really don't care that much about typedef'ing a usual construct
into a briefer mnemonic. As far as I know "ull" isn't a reserved
word or relevant to integer constants, it's not "ULL". Point being,
I don't really much care, then the point was more about using
incompatible integer conversions, and not just "arbitrary-precision",
plain old "fixed precision".
Heh, the tiff2pdf.c has been shelved and un-shelved a bunch of times
in the libtiff, like a couple years ago the maintainer was like
"I'm shelving this, build it yourself", then was like, "sorry, it's
back", point being it's a primitive sort of beginner's code I wrote
about 25 years ago, that you can find on the Internet. On comp.lang.java.programmer the other day, I wrote up how I write simple adapters for web-services, I've implemented hundreds of modules in Java, mostly to do one thing well and cut a hard dependency.
The re-routine idea for co-operative multi-threading instead of
co-routines is a great sort of idea, you can read about that on comp.lang.c++.
Then, about the mnemonics of assembler instructions, the idea is
to be making a "templating and typing assembler" as a pre-processor,
so that among various sorts of syntaxes and instruction codes,
to just have a common subset of those, since all sorts of machine architectures are so much alike.
I lived in the enterprise distributed space for at least a decade,
so, I've read quite a few million lines of code, and usually I've read
all the source code of the entire stack. Then, I've written some
millions of lines of code, and not counting "generated code", since
writing some generators and resulting arbitrarily many lines of code.
I'm familiar with the language standards. In fact,
I ever prefer "strict" quite usually.
I haven't been involved in making decisions to fire people for their
code quality, though one time my job was to make the firing machine go faster. I didn't really appreciate that, since then when my next job was
to fix a bug in the arbitration system, I found a bunch of their bugs,
and fixed them, then they were like, you know, embarrassed.
I did what they said, problem is they didn't know I'd do what I should.
I automatically detect obvious bugs.
I'm a full-stack enterprise dev, all-phases analysis, design, and implementation, thanks. Familiar with "500 page specs" a bit more
than "the 30,000 foot view". So, I know C/C++, and Java, and Perl and
Python and JavaScript or Typescript and a bit of Ruby or Go and of
course shell scripts and all their build systems and most of the little dotfile syntaxes, and of course "SQL", or how Oracle does it and a bit
of Postgres and MS for particulars, or for things like "the data
ware-house".
About encoding two integers in one integer, there are any number of ways
to do it, for example where they're on the same order and where they're
not on the same order, where one's best case is the other's worst case,
and vice versa. Sort of like big-end and little-end vis-a-vis 2-tuples.
I know binary.
On my video essays under "Logos 2000" there are some "Logos 2000:
software ..." bits, or "o.s. walkthrough" or something, since I study computer science also, and even a bit of computer engineering.
I.e., when I say "full-stack", I mean "the entire full-stack".
On 6/18/2026 12:21 AM, Ross Finlayson wrote:
[...]
I.e., when I say "full-stack", I mean "the entire full-stack".
Oh nice. copyright 2003? Right? But why the typedef to ull? Strange to
me. Anyway, yup. Got your chops. Also, your comment about C/C++ was odd
to me. They are completely different langs. Fwiw, one thing. I was
involved with creating the EventCount way back. Every used them before? Fwiw, read all of:
https://gist.github.com/mratsim/04a29bdd98d6295acda4d0677c4d0041
Its rather obscure. But shit happens. Sorry.
On 6/18/2026 12:21 AM, Ross Finlayson wrote:
[...]
I.e., when I say "full-stack", I mean "the entire full-stack".
Oh nice. copyright 2003? Right? But why the typedef to ull? Strange to
me. Anyway, yup. Got your chops. Also, your comment about C/C++ was odd
to me. They are completely different langs. Fwiw, one thing. I was
involved with creating the EventCount way back. Every used them before? Fwiw, read all of:
https://gist.github.com/mratsim/04a29bdd98d6295acda4d0677c4d0041
Its rather obscure. But shit happens. Sorry.
On 6/18/2026 12:21 AM, Ross Finlayson wrote:
[...]
I.e., when I say "full-stack", I mean "the entire full-stack".
Oh nice. copyright 2003? Right? But why the typedef to ull? Strange to
me. Anyway, yup. Got your chops. Also, your comment about C/C++ was odd
to me. They are completely different langs. Fwiw, one thing. I was
involved with creating the EventCount way back. Every used them before? Fwiw, read all of:
https://gist.github.com/mratsim/04a29bdd98d6295acda4d0677c4d0041
Its rather obscure. But shit happens. Sorry.
| Sysop: | Amessyroom |
|---|---|
| Location: | Fayetteville, NC |
| Users: | 70 |
| Nodes: | 6 (0 / 6) |
| Uptime: | 39:26:46 |
| Calls: | 948 |
| Calls today: | 2 |
| Files: | 1,325 |
| Messages: | 280,644 |