Blum integer
- Definition
A positive integer n is a Blum integer if n = p x q is a semi-prime for which p and q are distinct primes congruent to 3 mod 4. In other words, p and q must be of the form 4t + 3 where t is some non-negative integer.
- Example
21 is a Blum integer because it has two prime factors: 3 (= 4 x 0 + 3) and 7 (= 4 x 1 + 3).
- Task
Find and show on this page the first 50 Blum integers.
Also show the 26,828th.
- Stretch
Find and show the 100,000th, 200,000th, 300,000th and 400,000th Blum integers.
For the first 400,000 Blum integers, show the percentage distribution by final decimal digit (to 3 decimal places). Clearly, such integers can only end in 1, 3, 7 or 9.
- Related task
- References
- Wikipedia article Blum integer
- OEIS sequence A016105: Blum integers
ALGOL 68
If running this with ALGOL 68G, you will need to specify a larger heap size with -heap 256M
on the command line.
Builds tables of the unique prime factor counts and the last prime factor to handle the stretch goal, uses prime factorisation to find the first 50 Blum integers.
BEGIN # find Blum integers, semi-primes where both factors are 3 mod 4 #
# and the factors are distinct #
INT max number = 10 000 000; # maximum possible Blum we will consider #
[ 1 : max number ]INT upfc; # table of unique prime factor counts #
[ 1 : max number ]INT lpf; # table of last prime factors #
FOR i TO UPB upfc DO upfc[ i ] := 0; lpf[ i ] := 1 OD;
FOR i FROM 2 TO UPB upfc OVER 2 DO
FOR j FROM i + i BY i TO UPB upfc DO
upfc[ j ] +:= 1;
lpf[ j ] := i
OD
OD;
# returns TRUE if n is a Blum integer, FALSE otherwise #
PROC is blum = ( INT n )BOOL:
IF n < 21 THEN FALSE # the lowest primes modulo 4 that are 3 are #
# 3 & 7, so 21 is the lowest possible number #
ELIF NOT ODD n THEN FALSE
ELSE
INT v := n;
INT f count := 0;
INT f := 3;
WHILE f <= v AND f count < 3 DO
IF v MOD f = 0 THEN
IF f MOD 4 /= 3 THEN
f count := 9 # the prime factor mod 4 isn't 3 #
ELSE
v OVERAB f;
f count +:= 1
FI;
IF v MOD f = 0 THEN
f count := 9 # f is not a distinct factor of n #
FI
FI;
f +:= 2
OD;
f count = 2
FI # is blum # ;
# show various Blum integers #
print( ( "The first 50 Blum integers:", newline ) );
INT b count := 0;
[ 0 : 9 ]INT last count := []INT( 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 )[ AT 0 ];
FOR i FROM 21 WHILE b count < 400 000 DO
IF b count < 50 THEN
IF is blum( i ) THEN
b count +:= 1;
last count[ i MOD 10 ] +:= 1;
print( ( whole( i, -4 ) ) );
IF b count MOD 10 = 0 THEN print( ( newline ) ) FI
FI
ELIF upfc[ i ] = 2 THEN
# two unique prime factors - could be a Blum integer #
IF lpf[ i ] MOD 4 = 3 THEN
# the last prime factor mod 4 is three #
IF ( i OVER lpf[ i ] ) MOD 4 = 3 THEN
# and so is the other one #
b count +:= 1;
last count[ i MOD 10 ] +:= 1;
IF b count = 26 828
OR b count = 100 000
OR b count = 200 000
OR b count = 300 000
OR b count = 400 000
THEN
print( ( "The ", whole( b count, -6 )
, "th Blum integer is ", whole( i, -11 )
, newline
)
)
FI
FI
FI
FI
OD;
# show some statistics of the last digits #
print( ( "For Blum integers up to ", whole( b count, 0 ), ":", newline ) );
FOR i FROM LWB last count TO UPB last count DO
IF last count[ i ] /= 0 THEN
print( ( " ", fixed( ( last count[ i ] * 100 ) / b count, -8, 3 )
, "% end with ", whole( i, 0 )
, newline
)
)
FI
OD
END
- Output:
The first 50 Blum integers: 21 33 57 69 77 93 129 133 141 161 177 201 209 213 217 237 249 253 301 309 321 329 341 381 393 413 417 437 453 469 473 489 497 501 517 537 553 573 581 589 597 633 649 669 681 713 717 721 737 749 The 26828th Blum integer is 524273 The 100000th Blum integer is 2075217 The 200000th Blum integer is 4275533 The 300000th Blum integer is 6521629 The 400000th Blum integer is 8802377 For Blum integers up to 400000: 25.001% end with 1 25.017% end with 3 24.997% end with 7 24.985% end with 9
C
#include <stdio.h>
#include <stdbool.h>
#include <locale.h>
int inc[8] = {4, 2, 4, 2, 4, 6, 2, 6};
bool isPrime(int n) {
if (n < 2) return false;
if (n%2 == 0) return n == 2;
if (n%3 == 0) return n == 3;
int d = 5;
while (d*d <= n) {
if (n%d == 0) return false;
d += 2;
if (n%d == 0) return false;
d += 4;
}
return true;
}
// Assumes n is odd.
int firstPrimeFactor(int n) {
if (n == 1) return 1;
if (!(n%3)) return 3;
if (!(n%5)) return 5;
for (int k = 7, i = 0; k*k <= n; ) {
if (!(n%k)) {
return k;
} else {
k += inc[i];
i = (i + 1) % 8;
}
}
return n;
}
int main() {
int i = 1, j, bc = 0, p, q;
int blum[50], counts[4] = {0}, digits[4] = {1, 3, 5, 7};
setlocale(LC_NUMERIC, "");
while (true) {
p = firstPrimeFactor(i);
if (p % 4 == 3) {
q = i / p;
if (q != p && q % 4 == 3 && isPrime(q)) {
if (bc < 50) blum[bc] = i;
++counts[i % 10 / 3];
++bc;
if (bc == 50) {
printf("First 50 Blum integers:\n");
for (j = 0; j < 50; ++j) {
printf("%3d ", blum[j]);
if (!((j+1) % 10)) printf("\n");
}
printf("\n");
} else if (bc == 26828 || !(bc % 100000)) {
printf("The %'7dth Blum integer is: %'9d\n", bc, i);
if (bc == 400000) {
printf("\n%% distribution of the first 400,000 Blum integers:\n");
for (j = 0; j < 4; ++j) {
printf(" %6.3f%% end in %d\n", counts[j]/4000.0, digits[j]);
}
break;
}
}
}
}
i += (i % 5 == 3) ? 4 : 2;
}
return 0;
}
- Output:
Same as Wren example.
Go
package main
import (
"fmt"
"rcu"
)
var inc = []int{4, 2, 4, 2, 4, 6, 2, 6}
// Assumes n is odd.
func firstPrimeFactor(n int) int {
if n == 1 {
return 1
}
if n%3 == 0 {
return 3
}
if n%5 == 0 {
return 5
}
for k, i := 7, 0; k*k <= n; {
if n%k == 0 {
return k
} else {
k += inc[i]
i = (i + 1) % 8
}
}
return n
}
func main() {
blum := make([]int, 50)
bc := 0
counts := make([]int, 4)
i := 1
for {
p := firstPrimeFactor(i)
if p%4 == 3 {
q := i / p
if q != p && q%4 == 3 && rcu.IsPrime(q) {
if bc < 50 {
blum[bc] = i
}
counts[i%10/3]++
bc++
if bc == 50 {
fmt.Println("First 50 Blum integers:")
rcu.PrintTable(blum, 10, 3, false)
fmt.Println()
} else if bc == 26828 || bc%100000 == 0 {
fmt.Printf("The %7sth Blum integer is: %9s\n", rcu.Commatize(bc), rcu.Commatize(i))
if bc == 400000 {
fmt.Println("\n% distribution of the first 400,000 Blum integers:")
digits := []int{1, 3, 7, 9}
for j := 0; j < 4; j++ {
fmt.Printf(" %6.3f%% end in %d\n", float64(counts[j])/4000, digits[j])
}
return
}
}
}
}
if i%5 == 3 {
i += 4
} else {
i += 2
}
}
}
- Output:
Same as Wren example.
Julia
using Formatting, Primes
function isblum(n)
pe = factor(n).pe
i = length(pe)
return i == 2 && all(p -> p[2] == 1 && p[1] % 4 == 3, pe)
end
const blum400k = @view (filter(isblum, 1:9_000_000))[1:400_000]
println("First 50 Blum integers:")
foreach(p -> print(rpad(p[2], 4), p[1] % 10 == 0 ? "\n" : ""), enumerate(blum400k[1:50]))
for idx in [26_828, 100_000, 200_000, 300_000, 400_000]
println("\nThe $(format(idx, commas = true))th Blum number is ",
format(blum400k[idx], commas = true), ".")
end
println("\n% distribution of the first 400,000 Blum integers is:")
for d in [1, 3, 7, 9]
println(lpad(round(count(x -> x % 10 == d, blum400k) / 4000, digits=3), 8), "% end in $d")
end
- Output:
Same as Wren, Go, etc
Wren
import "./math" for Int
import "./fmt" for Fmt
var inc = [4, 2, 4, 2, 4, 6, 2, 6]
// Assumes n is odd.
var firstPrimeFactor = Fn.new { |n|
if (n == 1) return 1
if (n%3 == 0) return 3
if (n%5 == 0) return 5
var k = 7
var i = 0
while (k * k <= n) {
if (n%k == 0) {
return k
} else {
k = k + inc[i]
i = (i + 1) % 8
}
}
return n
}
var blum = List.filled(50, 0)
var bc = 0
var counts = { 1: 0, 3: 0, 7: 0, 9: 0 }
var i = 1
while (true) {
var p = firstPrimeFactor.call(i)
if (p % 4 == 3) {
var q = i / p
if (q != p && q % 4 == 3 && Int.isPrime(q)) {
if (bc < 50) blum[bc] = i
counts[i % 10] = counts[i % 10] + 1
bc = bc + 1
if (bc == 50) {
System.print("First 50 Blum integers:")
Fmt.tprint("$3d ", blum, 10)
System.print()
} else if (bc == 26828 || bc % 1e5 == 0) {
Fmt.print("The $,9r Blum integer is: $,9d", bc, i)
if (bc == 400000) {
System.print("\n\% distribution of the first 400,000 Blum integers:")
for (i in [1, 3, 7, 9]) {
Fmt.print(" $6.3f\% end in $d", counts[i]/4000, i)
}
return
}
}
}
}
i = (i % 5 == 3) ? i + 4 : i + 2
}
- Output:
First 50 Blum integers: 21 33 57 69 77 93 129 133 141 161 177 201 209 213 217 237 249 253 301 309 321 329 341 381 393 413 417 437 453 469 473 489 497 501 517 537 553 573 581 589 597 633 649 669 681 713 717 721 737 749 The 26,828th Blum integer is: 524,273 The 100,000th Blum integer is: 2,075,217 The 200,000th Blum integer is: 4,275,533 The 300,000th Blum integer is: 6,521,629 The 400,000th Blum integer is: 8,802,377 % distribution of the first 400,000 Blum integers is: 25.001% end in 1 25.017% end in 3 24.997% end in 7 24.985% end in 9
XPL0
Simple minded brute force takes 93 seconds on Pi4.
int Prime1;
func Semiprime(N); \Return 'true' if N is semiprime
int N, F, C;
[C:= 0; F:= 2;
repeat if rem(N/F) = 0 then
[C:= C+1;
Prime1:= N;
N:= N/F;
]
else F:= F+1;
until F > N;
return C = 2;
];
int N, C, Prime2;
[Format(4,0);
N:= 3; C:= 0;
loop [if Semiprime(N) then
[if rem(Prime1/4) = 3 then
[Prime2:= N/Prime1;
if Prime2 # Prime1 and rem(Prime2/4) = 3 then
[C:= C+1;
if C <= 50 then
[RlOut(0, float(N));
if rem(C/10) = 0 then CrLf(0);
];
if rem(C/1000)=0 then ChOut(0, ^.);
if C >= 26828 then
[Text(0, "^m^jThe 26828th Blum integer is: ");
IntOut(0, N); CrLf(0);
quit;
];
];
];
];
N:= N+2;
];
]
- Output:
21 33 57 69 77 93 129 133 141 161 177 201 209 213 217 237 249 253 301 309 321 329 341 381 393 413 417 437 453 469 473 489 497 501 517 537 553 573 581 589 597 633 649 669 681 713 717 721 737 749 .......................... The 26828th Blum integer is: 524273