⚠️ Warning: This is a draft ⚠️
This means it might contain formatting issues, incorrect code, conceptual problems, or other severe issues.
If you want to help to improve and eventually enable this page, please fork RosettaGit's repository and open a merge request on GitHub.
{{task|Prime Numbers}}
Semiprime numbers are natural numbers that are products of exactly two (possibly equal) [[prime_number|prime numbers]].
'''Semiprimes''' are also known as: :::* '''semi-primes''' :::* '''biprimes''' :::* '''bi-primes''' :::* ''' ''2-almost'' ''' primes :::* or simply: ''' ''P2 '' '''
;Example: 1679 = 23 × 73
(This particular number was chosen as the length of the [http://en.wikipedia.org/wiki/Arecibo_message Arecibo message]).
;Task; Write a function determining whether a given number is semiprime.
;See also:
- The Wikipedia article: [http://mathworld.wolfram.com/Semiprime.html semiprime].
- The Wikipedia article: [http://mathworld.wolfram.com/AlmostPrime.html almost prime].
- The OEIS article: [http://oeis.org/A001358 semiprimes] which has a shorter definition: ''the product of two primes''.
360 Assembly
{{trans|C}}
* Semiprime 14/03/2017
SEMIPRIM CSECT
USING SEMIPRIM,R13 base register
B 72(R15) skip savearea
DC 17F'0' savearea
STM R14,R12,12(R13) save previous context
ST R13,4(R15) link backward
ST R15,8(R13) link forward
LR R13,R15 set addressability
LA R10,PG pgi=0
LA R8,0 m=0
L R6,=F'2' i=2
DO WHILE=(C,R6,LE,=F'100') do i=2 to 100
ST R6,N n=i
LA R9,0 f=0
LA R7,2 j=2
LOOPJ EQU * do j=2 while f<2 and j*j<=n
C R9,=F'2' if f<2
BNL EXITJ then exit do j
LR R5,R7 j
MR R4,R7 *j
C R5,N if j*j<=n
BH EXITJ then exit do j
LOOPK EQU * do while n mod j=0
L R4,N n
SRDA R4,32 ~
DR R4,R7 /j
LTR R4,R4 if n mod <>0
BNZ EXITK then exit do j
ST R5,N n=n/j
LA R9,1(R9) f=f+1
B LOOPK enddo k
EXITK LA R7,1(R7) j++
B LOOPJ enddo j
EXITJ L R4,N n
IF C,R4,GT,=F'1' THEN if n>1 then
LA R2,1 g=1
ELSE , else
LA R2,0 g=0
ENDIF , endif
AR R2,R9 +f
IF C,R2,EQ,=F'2' THEN if f+(n>1)=2 then
XDECO R6,XDEC edit i
MVC 0(5,R10),XDEC+7 output i
LA R10,5(R10) pgi=pgi+10
LA R8,1(R8) m=m+1
LR R4,R8 m
SRDA R4,32 ~
D R4,=F'16' m/16
IF LTR,R4,Z,R4 THEN if m mod 16=0 then
XPRNT PG,L'PG print buffer
MVC PG,=CL80' ' clear buffer
LA R10,PG pgi=0
ENDIF , endif
ENDIF , endif
LA R6,1(R6) i++
ENDDO , enddo i
XPRNT PG,L'PG print buffer
MVC PG,=CL80'..... semiprimes' init buffer
XDECO R8,XDEC edit m
MVC PG(5),XDEC+7 output m
XPRNT PG,L'PG print buffer
L R13,4(0,R13) restore previous savearea pointer
LM R14,R12,12(R13) restore previous context
XR R15,R15 rc=0
BR R14 exit
N DS F n
PG DC CL80' ' buffer
XDEC DS CL12 temp
YREGS
END SEMIPRIM
{{out}}
4 6 9 10 14 15 21 22 25 26 33 34 35 38 39 46
49 51 55 57 58 62 65 69 74 77 82 85 86 87 91 93
94 95
34 semiprimes
Ada
This imports the package '''Prime_Numbers''' from [[Prime decomposition#Ada]].
with Prime_Numbers, Ada.Text_IO;
procedure Test_Semiprime is
package Integer_Numbers is new
Prime_Numbers (Natural, 0, 1, 2);
use Integer_Numbers;
begin
for N in 1 .. 100 loop
if Decompose(N)'Length = 2 then -- N is a semiprime;
Ada.Text_IO.Put(Integer'Image(Integer(N)));
end if;
end loop;
Ada.Text_IO.New_Line;
for N in 1675 .. 1680 loop
if Decompose(N)'Length = 2 then -- N is a semiprime;
Ada.Text_IO.Put(Integer'Image(Integer(N)));
end if;
end loop;
end Test_Semiprime;
It outputs all semiprimes below 100 and all semiprimes between 1675 and 1680: {{output}} 4 6 9 10 14 15 21 22 25 26 33 34 35 38 39 46 49 51 55 57 58 62 65 69 74 77 82 85 86 87 91 93 94 95 1678 1679
Note that 1675 = 5 * 5 * 67, 1676 = 2 * 2 * 419, 1677 = 3 * 13 * 43, 1678 = 2 * 839, 1679 = 23 * 73, 1680 = 2 * 2 * 2 * 2 * 3 * 5 * 7, so the result printed is actually correct.
ALGOL 68
# returns TRUE if n is semi-prime, FALSE otherwise #
# n is semi prime if it has exactly two prime factors #
PROC is semiprime = ( INT n )BOOL:
BEGIN
# We only need to consider factors between 2 and #
# sqrt( n ) inclusive. If there is only one of these #
# then it must be a prime factor and so the number #
# is semi prime #
INT factor count := 0;
FOR factor FROM 2 TO ENTIER sqrt( ABS n )
WHILE IF n MOD factor = 0 THEN
factor count +:= 1;
# check the factor isn't a repeated factor #
IF n /= factor * factor THEN
# the factor isn't the square root #
INT other factor = n OVER factor;
IF other factor MOD factor = 0 THEN
# have a repeated factor #
factor count +:= 1
FI
FI
FI;
factor count < 2
DO SKIP OD;
factor count = 1
END # is semiprime # ;
# determine the first few semi primes #
print( ( "semi primes below 100: " ) );
FOR i TO 99 DO
IF is semi prime( i ) THEN print( ( whole( i, 0 ), " " ) ) FI
OD;
print( ( newline ) );
print( ( "semi primes below between 1670 and 1690: " ) );
FOR i FROM 1670 TO 1690 DO
IF is semi prime( i ) THEN print( ( whole( i, 0 ), " " ) ) FI
OD;
print( ( newline ) )
{{out}}
semi primes below 100: 4 6 9 10 14 15 21 22 25 26 33 34 35 38 39 46 49 51 55 57 58 62 65 69 74 77 82 85 86 87 91 93 94 95
semi primes below between 1670 and 1690: 1671 1673 1678 1679 1681 1685 1687 1689
AutoHotkey
{{works with|AutoHotkey_L}}
SetBatchLines -1
k := 1
loop, 100
{
m := semiprime(k)
StringSplit, m_m, m, -
if ( m_m1 = "yes" )
list .= k . " "
k++
}
MsgBox % list
list :=
;
### =============================================================================================================================
k := 1675
loop, 5
{
m := semiprime(k)
StringSplit, m_m, m, -
if ( m_m1 = "yes" )
list1 .= semiprime(k) . "`n"
else
list1 .= semiprime(k) . "`n"
k++
}
MsgBox % list1
list1 :=
;
### =============================================================================================================================
; The function
### ====================================================================================================================
semiprime(k)
{
start := floor(sqrt(k))
loop, % floor(sqrt(k)) - 1
{
if ( mod(k, start) = 0 )
new .= floor(start) . "*" . floor(k//start) . ","
start--
}
StringSplit, index, new, `,
if ( index0 = 2 )
{
StringTrimRight, new, new, 1
StringSplit, 2_ind, new, *
if (mod(2_ind2, 2_ind1) = 0) && ( 2_ind1 != 2_ind2 )
new := "N0- " . k . " - " . new
else
new := "yes- " . k . " - " . new
}
else
new := "N0- " . k . " - " . new
return new
}
;
### ===========================================================================================================================================
esc::Exitapp
{{output}}
4 6 9 10 14 15 21 22 25 26 33 34 35 38 39 46 49 51 55 57 58 62 65 69 74 77 82 85 86 87 91 93 94 95 N0- 1675 - 25*67,5*335, N0- 1676 - 4*419,2*838, N0- 1677 - 39*43,13*129,3*559, yes- 1678 - 2*839 yes- 1679 - 23*73## AWK ```AWK # syntax: GAWK -f SEMIPRIME.AWK BEGIN { main(0,100) main(1675,1680) exit(0) } function main(lo,hi, i) { printf("%d-%d:",lo,hi) for (i=lo; i<=hi; i++) { if (is_semiprime(i)) { printf(" %d",i) } } printf("\n") } function is_semiprime(n, i,nf) { nf = 0 for (i=2; i<=n; i++) { while (n % i == 0) { if (nf == 2) { return(0) } nf++ n /= i } } return(nf == 2) } ``` {{out}} ```txt 0-100: 4 6 9 10 14 15 21 22 25 26 33 34 35 38 39 46 49 51 55 57 58 62 65 69 74 77 82 85 86 87 91 93 94 95 1675-1680: 1678 1679 ``` ## Bracmat When Bracmat is asked to take the square (or any other) root of a number, it does so by first finding the number's prime factors. It can do that for numbers up to 2^32 or 2^64 (depending on compiler and processor). ```bracmat semiprime= m n a b . 2^-64:?m & 2*!m:?n & !arg^!m : (#%?a^!m*#%?b^!m|#%?a^!n&!a:?b) & (!a.!b); ``` Test with numbers < 2^63: ```bracmat 2^63:?u & whl ' ( -1+!u:>2:?u & ( semiprime$!u:?R&out$(!u ":" !R) | ) ); ``` Output: ```txt 9223372036854775797 : (3.3074457345618258599) 9223372036854775777 : (584911.15768846947407) 9223372036854775771 : (19.485440633518672409) 9223372036854775753 : (266416229.34620158357) 9223372036854775727 : (11113.829962389710679) 9223372036854775717 : (59.156328339607708063) 9223372036854775715 : (5.1844674407370955143) 9223372036854775703 : (9648151.955973018753) 9223372036854775694 : (2.4611686018427387847) 9223372036854775691 : (37.249280325320399343) 9223372036854775687 : (1303.7078566413549329) 9223372036854775685 : (5.1844674407370955137) 9223372036854775673 : (175934777.52424950849) 9223372036854775634 : (2.4611686018427387817) 9223372036854775633 : (421741.21869754273013) 9223372036854775627 : (6277.1469391753521551) 9223372036854775609 : (172153.53576597775553) 9223372036854775601 : (1045692671.8820346831) 9223372036854775589 : (563.16382543582335303) 9223372036854775577 : (267017141.34542246997) 9223372036854775574 : (2.4611686018427387787) 9223372036854775571 : (1951.4727510013764621) 9223372036854775537 : (47.196241958230952671) 9223372036854775531 : (1677122561.5499521771) 9223372036854775522 : (2.4611686018427387761) 9223372036854775511 : (29305709.314729530579) 9223372036854775502 : (2.4611686018427387751) 9223372036854775489 : (9413717.979780041917) 9223372036854775474 : (2.4611686018427387737) 9223372036854775466 : (2.4611686018427387733) 9223372036854775461 : (3.3074457345618258487) 9223372036854775451 : (545369243.16912160257) 9223372036854775439 : (11380717.810438572267) 9223372036854775418 : (2.4611686018427387709) 9223372036854775411 : (1420967.6490912200533) 9223372036854775409 : (15060911.612404657119) 9223372036854775407 : (3.3074457345618258469) 9223372036854775402 : (2.4611686018427387701) 9223372036854775389 : (3.3074457345618258463) 9223372036854775385 : (5.1844674407370955077) 9223372036854775383 : (3.3074457345618258461) 9223372036854775381 : (683.13504205031998207) 9223372036854775379 : (43.214497024112901753) 9223372036854775357 : (17.542551296285575021) 9223372036854775355 : (5.1844674407370955071) ^CTerminate batch job (Y/N)? Y ``` ## C ```c #include
factorint
), so this version is in PARI:
```c
long
issemiprime(GEN n)
{
if (typ(n) != t_INT)
pari_err_TYPE("issemiprime", n);
if (signe(n) <= 0)
return 0;
ulong nn = itou_or_0(n);
if (nn)
return uissemiprime(nn);
pari_sp ltop = avma;
if (!mpodd(n)) {
long ret = mod4(n) && isprime(shifti(n, -1));
avma = ltop;
return ret;
}
long p;
forprime_t primepointer;
u_forprime_init(&primepointer, 3, 997);
while ((p = u_forprime_next(&primepointer))) {
if (dvdis(n, p)) {
long ret = isprime(diviuexact(n, p));
avma = ltop;
return ret;
}
}
if (isprime(n))
return 0;
if (DEBUGLEVEL > 3)
pari_printf("issemi: Number is a composite with no small prime factors; using general factoring mechanisms.");
GEN fac = Z_factor_until(n, shifti(n, -1)); /* Find a nontrivial factor -- returns just the factored part */
GEN expo = gel(fac, 2);
GEN pr = gel(fac, 1);
long len = glength(expo);
if (len > 2) {
avma = ltop;
return 0;
}
if (len == 2) {
if (cmpis(gel(expo, 1), 1) > 0 || cmpis(gel(expo, 2), 1) > 0) {
avma = ltop;
return 0;
}
GEN P = gel(pr, 1);
GEN Q = gel(pr, 2);
long ret = isprime(P) && isprime(Q) && equalii(mulii(P, Q), n);
avma = ltop;
return ret;
}
if (len == 1) {
long e = itos(gel(expo, 1));
if (e == 2) {
GEN P = gel(pr, 1);
long ret = isprime(P) && equalii(sqri(P), n);
avma = ltop;
return ret;
} else if (e > 2) {
avma = ltop;
return 0;
}
GEN P = gel(pr, 1);
long ret = isprime(P) && isprime(diviiexact(n, P));
avma = ltop;
return ret;
}
pari_err_BUG(pari_sprintf("Z_factor_until returned an unexpected value %Ps at n = %Ps, exiting...", fac, n));
avma = ltop;
return 0; /* never used */
}
```
## Pascal
{{libheader|primTrial}}{{works with|Free Pascal}}
```pascal
program SemiPrime;
{$IFDEF FPC}
{$Mode objfpc}// compiler switch to use result
{$ELSE}
{$APPTYPE CONSOLE} // for Delphi
{$ENDIF}
uses
primTrial;
function isSemiprime(n: longWord;doWrite:boolean): boolean;
var
fac1 : LongWord;
begin
//a simple isAlmostPrime(n,2) would do without output;
fac1 := SmallFactor(n);
IF fac1 < n then
Begin
n := n div fac1;
result := SmallFactor(n) = n;
if result AND doWrite then
write(fac1:10,'*',n:11)
end
else
result := false;
end;
var
i,k : longWord;
BEGIN
For i := 2 to 97 do
IF isSemiPrime(i,false) then
write(i:3);
writeln;
//test for big numbers
k := 4000*1000*1000;
i := k-100;
repeat
IF isSemiPrime(i,true) then
writeln(' = ',i:10);
inc(i);
until i> k;
END.
```
;output:
```txt
4 6 9 10 14 15 21 22 25 26 33 34 35 38 39 46 49 51 55 57 58 62 65 69
74 77 82 85 86 87 91 93 94 95
71* 56338027 = 3999999917
42307* 94547 = 3999999929
59* 67796609 = 3999999931
5* 799999987 = 3999999935
2* 1999999973 = 3999999946
11* 363636359 = 3999999949
103* 38834951 = 3999999953
12007* 333139 = 3999999973
7* 571428569 = 3999999983
5* 799999999 = 3999999995
```
## Perl
{{libheader|ntheory}}
With late versions of the ntheory module, we can use is_semiprime to get answers for 64-bit numbers in single microseconds.
```perl
use ntheory "is_semiprime";
for ([1..100], [1675..1681], [2,4,99,100,1679,5030,32768,1234567,9876543,900660121]) {
print join(" ",grep { is_semiprime($_) } @$_),"\n";
}
```
{{out}}
```txt
4 6 9 10 14 15 21 22 25 26 33 34 35 38 39 46 49 51 55 57 58 62 65 69 74 77 82 85 86 87 91 93 94 95
1678 1679 1681
4 1679 1234567 900660121
```
One can also use factor in scalar context, which gives the number of factors (like bigomega in Pari/GP and PrimeOmega in Mathematica). This skips some optimizations but at these small sizes it doesn't matter.
```perl
use ntheory "factor";
print join(" ", grep { scalar factor($_) == 2 } 1..100),"\n";
```
While is_semiprime is the fastest way, we can do some of its pre-tests by hand, such as:
```perl
use ntheory qw/factor is_prime trial_factor/;
sub issemi {
my $n = shift;
if ((my @p = trial_factor($n,500)) > 1) {
return 0 if @p > 2;
return !!is_prime($p[1]) if @p == 2;
}
2 == factor($n);
}
```
## Perl 6
Here is a naive, grossly inefficient implementation.
```perl6
sub is-semiprime (Int $n --> Bool) {
not $n.is-prime and
.is-prime given
$n div first $n %% *, flat grep &is-prime, 2 .. *;
}
use Test;
my @primes = flat grep &is-prime, 2 .. 100;
for ^5 {
nok is-semiprime([*] my @f1 = @primes.roll(1)), ~@f1;
ok is-semiprime([*] my @f2 = @primes.roll(2)), ~@f2;
nok is-semiprime([*] my @f3 = @primes.roll(3)), ~@f3;
nok is-semiprime([*] my @f4 = @primes.roll(4)), ~@f4;
}
```
{{out}}
```txt
ok 1 - 17
ok 2 - 47 23
ok 3 - 23 37 41
ok 4 - 53 37 67 47
ok 5 - 5
ok 6 - 73 43
ok 7 - 13 53 71
ok 8 - 7 79 37 71
ok 9 - 41
ok 10 - 71 37
ok 11 - 37 53 43
ok 12 - 3 2 47 67
ok 13 - 17
ok 14 - 41 61
ok 15 - 71 31 79
ok 16 - 97 17 73 17
ok 17 - 61
ok 18 - 73 47
ok 19 - 13 19 5
ok 20 - 37 97 11 31
```
### More efficient example
Here is a more verbose, but MUCH more efficient implementation. Demonstrating using it to find an infinite list of semiprimes and to check a range of integers to find the semiprimes.
{{works with|Rakudo|2017.02}}
```perl6
sub is-semiprime ( Int $n where * > 0 ) {
return False if $n.is-prime;
my $factor = find-factor( $n );
return True if $factor.is-prime && ( $n div $factor ).is-prime;
False;
}
sub find-factor ( Int $n, $constant = 1 ) {
my $x = 2;
my $rho = 1;
my $factor = 1;
while $factor == 1 {
$rho *= 2;
my $fixed = $x;
for ^$rho {
$x = ( $x * $x + $constant ) % $n;
$factor = ( $x - $fixed ) gcd $n;
last if 1 < $factor;
}
}
$factor = find-factor( $n, $constant + 1 ) if $n == $factor;
$factor;
}
INIT my $start = now;
# Infinite list of semiprimes
constant @semiprimes = lazy gather for 4 .. * { .take if .&is-semiprime };
# Show the semiprimes < 100
say 'Semiprimes less than 100:';
say @semiprimes[^ @semiprimes.first: * > 100, :k ], "\n";
# Check individual integers, or in this case, a range
my $s = 2⁹⁷ - 1;
say "Is $_ semiprime?: ", .&is-semiprime for $s .. $s + 30;
say 'elapsed seconds: ', now - $start;
```
{{out}}
```txt
Semiprimes less than 100:
(4 6 9 10 14 15 21 22 25 26 33 34 35 38 39 46 49 51 55 57 58 62 65 69 74 77 82 85 86 87 91 93 94 95)
Is 158456325028528675187087900671 semiprime?: True
Is 158456325028528675187087900672 semiprime?: False
Is 158456325028528675187087900673 semiprime?: False
Is 158456325028528675187087900674 semiprime?: False
Is 158456325028528675187087900675 semiprime?: False
Is 158456325028528675187087900676 semiprime?: False
Is 158456325028528675187087900677 semiprime?: False
Is 158456325028528675187087900678 semiprime?: False
Is 158456325028528675187087900679 semiprime?: False
Is 158456325028528675187087900680 semiprime?: False
Is 158456325028528675187087900681 semiprime?: False
Is 158456325028528675187087900682 semiprime?: False
Is 158456325028528675187087900683 semiprime?: False
Is 158456325028528675187087900684 semiprime?: False
Is 158456325028528675187087900685 semiprime?: False
Is 158456325028528675187087900686 semiprime?: False
Is 158456325028528675187087900687 semiprime?: False
Is 158456325028528675187087900688 semiprime?: False
Is 158456325028528675187087900689 semiprime?: False
Is 158456325028528675187087900690 semiprime?: False
Is 158456325028528675187087900691 semiprime?: False
Is 158456325028528675187087900692 semiprime?: False
Is 158456325028528675187087900693 semiprime?: False
Is 158456325028528675187087900694 semiprime?: False
Is 158456325028528675187087900695 semiprime?: False
Is 158456325028528675187087900696 semiprime?: False
Is 158456325028528675187087900697 semiprime?: False
Is 158456325028528675187087900698 semiprime?: False
Is 158456325028528675187087900699 semiprime?: False
Is 158456325028528675187087900700 semiprime?: False
Is 158456325028528675187087900701 semiprime?: True
elapsed seconds: 0.0574433
```
## Phix
```Phix
function semiprime(integer n)
sequence f = prime_factors(n)
integer l = length(f)
return (l=2 and n=f[1]*f[2]) or (l=1 and n=power(f[1],2))
end function
procedure test(integer start, integer stop)
sequence s = {}
for i=start to stop do
if semiprime(i) then
s &= i
end if
end for
?s
?length(s)
end procedure
test(1,100)
test(1675,1680)
```
```txt
{4,6,9,10,14,15,21,22,25,26,33,34,35,38,39,46,49,51,55,57,58,62,65,69,74,77,82,85,86,87,91,93,94,95}
34
{1678,1679}
2
```
## PicoLisp
```PicoLisp
(de factor (N)
(make
(let
(D 2
L (1 2 2 . (4 2 4 2 4 6 2 6 .))
M (sqrt N) )
(while (>= M D)
(if (=0 (% N D))
(setq M
(sqrt (setq N (/ N (link D)))) )
(inc 'D (pop 'L)) ) )
(link N) ) ) )
(println
(filter
'((X)
(let L (factor X)
(and (cdr L) (not (cddr L))) ) )
(conc (range 1 100) (range 1675 1680)) ) )
(bye)
```
{{out}}
```txt
(4 6 9 10 14 15 21 22 25 26 33 34 35 38 39 46 49 51 55 57 58 62 65 69 74 77 82 85 86 87 91 93 94 95 1678 1679)
```
## PL/I
```pli
*process source attributes xref nest or(!);
/*--------------------------------------------------------------------
* 22.02.2014 Walter Pachl using the is_prime code from
* PL/I 'prime decomposition'
* 23.02. WP start test for second prime with 2 or first prime found
*-------------------------------------------------------------------*/
spb: Proc options(main);
Dcl a(10) Bin Fixed(31)
Init(900660121,2,4,1679,1234567,32768,99,9876543,100,5040);
Dcl (x,n,nf,i,j) Bin Fixed(31) Init(0);
Dcl f(3) Bin Fixed(31);
Dcl txt Char(30) Var;
Dcl bit Bit(1);
Do i=1 To hbound(a);
bit=is_semiprime(a(i));
Select(nf);
When(0,1) txt=' is prime';
When(2) txt=' is semiprime '!!factors(a(i));
Otherwise txt=' is NOT semiprime '!!factors(a(i));
End;
Put Edit(a(i),bit,txt)(Skip,f(10),x(1),b(1),a);
End;
is_semiprime: Proc(x) Returns(bit(1));
/*--------------------------------------------------------------------
* Returns '1'b if x is semiprime, '0'b otherwise
* in addition
* it sets f(1) and f(2) to the first (or only) prime factor(s)
*-------------------------------------------------------------------*/
Dcl x Bin Fixed(31);
nf=0;
f=0;
x=a(i);
n=x;
f(1)=2;
loop:
Do While(nf<=2 & n>1);
If is_prime(n) Then Do;
Call mem(n);
Leave loop;
End;
Else Do;
loop2:
Do j=f(1) By 1 While(j*j<=n);
If is_prime(j)&mod(n,j)=0 Then Do;
Call mem(j);
n=n/j;
Leave loop2;
End;
End;
End;
End;
Return(nf=2);
End;
is_prime: Proc(n) Returns(bit(1));
Dcl n Bin Fixed(31);
Dcl i Bin Fixed(31);
If n < 2 Then Return('0'b);
If n = 2 Then Return('1'b);
If mod(n,2)=0 Then Return('0'b);
Do i = 3 by 2 While(i*i<=n);
If mod(n,i)=0 Then Return('0'b);
End;
Return('1'b);
End is_prime;
mem: Proc(x);
Dcl x Bin Fixed(31);
nf+=1;
f(nf)=x;
End;
factors: Proc(x) Returns(Char(150) Var);
Dcl x Bin Fixed(31);
Dcl (res,net) Char(150) Var Init('');
Dcl (i,f3) Bin Fixed(31);
res=f(1)!!'*'!!f(2);
f3=x/(f(1)*f(2));
If f3>1 Then
res=res!!'*'!!f3;
Do i=1 To length(res);
If substr(res,i,1)>' ' Then
net=net!!substr(res,i,1);
End;
Return(net);
End;
End spb;
```
'''Output:'''
```txt
900660121 1 is semiprime 30011*30011
2 0 is prime
4 1 is semiprime 2*2
1679 1 is semiprime 23*73
1234567 1 is semiprime 127*9721
32768 0 is NOT semiprime 2*2*8192
99 0 is NOT semiprime 3*3*11
9876543 0 is NOT semiprime 3*227*14503
100 0 is NOT semiprime 2*2*25
5040 0 is NOT semiprime 2*2*1260
```
## PowerShell
```PowerShell
function isPrime ($n) {
if ($n -le 1) {$false}
elseif (($n -eq 2) -or ($n -eq 3)) {$true}
else{
$m = [Math]::Floor([Math]::Sqrt($n))
(@(2..$m | where {($_ -lt $n) -and ($n % $_ -eq 0) }).Count -eq 0)
}
}
function semiprime ($n) {
if($n -gt 3) {
$lim = [Math]::Floor($n/2)+1
$i = 2
while(($i -lt $lim) -and ($n%$i -ne 0)){ $i += 1}
if($i -eq $lim){@()}
elseif(-not (isPrime ($n/$i))){@()}
else{@($i,($n/$i))}
} else {@()}
}
$OFS = " x "
"1679: $(semiprime 1679)"
"87: $(semiprime 87)"
"25: $(semiprime 25)"
"12: $(semiprime 12)"
"6: $(semiprime 6)"
$OFS = " "
"semiprime form 1 to 100: $(1..100 | where {semiprime $_})"
```
Output:
```txt
1679: 23 x 73
87: 3 x 29
25: 5 x 5
12:
6: 2 x 3
semiprime form 1 to 100: 4 6 9 10 14 15 21 22 25 26 33 34 35 38 39 46 49 51 55 57 58 62 65 69 74 77 82 85 86 87 91 93 94 95
```
## Python
This imports [[Prime decomposition#Python]]
```python
from prime_decomposition import decompose
def semiprime(n):
d = decompose(n)
try:
return next(d) * next(d) == n
except StopIteration:
return False
```
{{out}}
From Idle:
```python>>>
semiprime(1679)
True
>>> [n for n in range(1,101) if semiprime(n)]
[4, 6, 9, 10, 14, 15, 21, 22, 25, 26, 33, 34, 35, 38, 39, 46, 49, 51, 55, 57, 58, 62, 65, 69, 74, 77, 82, 85, 86, 87, 91, 93, 94, 95]
>>>
```
## Racket
The first implementation considers all pairs of factors multiplying up to the given number and determines if any of them is a pair of primes.
```Racket
#lang racket
(require math)
(define (pair-factorize n)
"Return all two-number factorizations of a number"
(let ([up-limit (integer-sqrt n)])
(map (λ (x) (list x (/ n x)))
(filter (λ (x) (<= x up-limit)) (divisors n)))))
(define (semiprime n)
"Determine if a number is semiprime i.e. a product of two primes.
Check if any pair of complete factors consists of primes."
(for/or ((pair (pair-factorize n)))
(for/and ((el pair))
(prime? el))))
```
The alternative implementation operates directly on the list of prime factors and their multiplicities. It is approximately 1.6 times faster than the first one (according to some simple tests of mine).
```Racket
#lang racket
(require math)
(define (semiprime n)
"Alternative implementation.
Check if there are two prime factors whose product is the argument
or if there is a single prime factor whose square is the argument"
(let ([prime-factors (factorize n)])
(or (and (= (length prime-factors) 1)
(= (expt (caar prime-factors) (cadar prime-factors)) n))
(and (= (length prime-factors) 2)
(= (foldl (λ (x y) (* (car x) y)) 1 prime-factors) n)))))
```
## REXX
### version 1
```rexx
/* REXX ---------------------------------------------------------------
* 20.02.2014 Walter Pachl relying on 'prime decomposition'
* 21.02.2014 WP Clarification: I copied the algorithm created by
* Gerard Schildberger under the task referred to above
* 21.02.2014 WP Make sure that factr is not called illegally
*--------------------------------------------------------------------*/
Call test 4
Call test 9
Call test 10
Call test 12
Call test 1679
Exit
test:
Parse Arg z
If is_semiprime(z) Then Say z 'is semiprime' fl
Else Say z 'is NOT semiprime' fl
Return
is_semiprime:
Parse Arg z
If z<1 | datatype(z,'W')=0 Then Do
Say 'Argument ('z') must be a natural number (1, 2, 3, ...)'
fl=''
End
Else
fl=factr(z)
Return words(fl)=2
/*----------------------------------FACTR subroutine-----------------*/
factr: procedure; parse arg x 1 z,list /*sets X&Z to arg1, LIST=''. */
if x==1 then return '' /*handle the special case of X=1.*/
j=2; call .factr /*factor for the only even prime.*/
j=3; call .factr /*factor for the 1st odd prime.*/
j=5; call .factr /*factor for the 2nd odd prime.*/
j=7; call .factr /*factor for the 3rd odd prime.*/
j=11; call .factr /*factor for the 4th odd prime.*/
j=13; call .factr /*factor for the 5th odd prime.*/
j=17; call .factr /*factor for the 6th odd prime.*/
/* [?] could be optimized more.*/
/* [?] J in loop starts at 17+2*/
do y=0 by 2; j=j+2+y//4 /*insure J isn't divisible by 3. */
if right(j,1)==5 then iterate /*fast check for divisible by 5. */
if j*j>z then leave /*are we higher than the v of Z ?*/
if j>Z then leave /*are we higher than value of Z ?*/
call .factr /*invoke .FACTR for some factors.*/
end /*y*/ /* [?] only tests up to the v X.*/
/* [?] LIST has a leading blank.*/
if z==1 then return list /*if residual=unity, don't append*/
return list z /*return list, append residual. */
/*-------------------------------.FACTR internal subroutine----------*/
.factr: do while z//j==0 /*keep dividing until we can't. */
list=list j /*add number to the list (J). */
z=z%j /*% (percent) is integer divide.*/
end /*while z··· */ /* // ?---remainder integer ÷.*/
return /*finished, now return to invoker*/
```
'''Output'''
```txt
4 is semiprime 2 2
9 is semiprime 3 3
10 is semiprime 2 5
12 is NOT semiprime 2 2 3
1679 is semiprime 23 73
```
### version 2
The method used is to examine integers, skipping primes.
If it's composite (the 1st factor is prime), then check if the 2nd factor is prime. If so, the number is a ''semiprime''.
The '''isPrime''' function could be optimized by utilizing an integer square root function instead of testing if '''j*j>x''' for every divisor.
```rexx
/*REXX program determines if any integer (or a range of integers) is/are semiprime. */
parse arg bot top . /*obtain optional arguments from the CL*/
if bot=='' | bot=="," then bot=random() /*None given? User wants us to guess.*/
if top=='' | top=="," then top=bot /*maybe define a range of numbers. */
tell= top=>0 | top==bot /*should results be shown to the term? */
w=max(length(bot), length(top)) + 5 /*obtain the maximum width of numbers. */
numeric digits max(9, w) /*ensure there're enough decimal digits*/
#=0 /*initialize number of semiprimes found*/
do n=bot to abs(top) /*show results for a range of numbers. */
?=isSemiPrime(n); #=#+? /*Is N a semiprime?; Maybe bump counter*/
if tell then say right(n,w) right(word("isn't" 'is', ?+1), 6) 'semiprime.'
end /*n*/
say
if bot\==top then say 'found ' # " semiprimes."
exit /*stick a fork in it, we're all done. */
/*──────────────────────────────────────────────────────────────────────────────────────*/
isPrime: procedure; parse arg x; if x<2 then return 0 /*number too low?*/
if wordpos(x, '2 3 5 7 11 13 17 19 23')\==0 then return 1 /*it's low prime.*/
if x//2==0 then return 0; if x//3==0 then return 0 /*÷ by 2; ÷ by 3?*/
do j=5 by 6 until j*j>x; if x//j==0 then return 0 /*not a prime. */
if x//(j+2)==0 then return 0 /* " " " */
end /*j*/
return 1 /*indicate that X is a prime number. */
/*──────────────────────────────────────────────────────────────────────────────────────*/
isSemiPrime: procedure; parse arg x; if x<4 then return 0
do i=2 for 2; if x//i==0 then if isPrime(x%i) then return 1
else return 0
end /*i*/
/* ___ */
do j=5 by 6; if j*j>x then return 0 /* > √ x ?*/
do k=j by 2 for 2; if x//k==0 then if isPrime(x%k) then return 1
else return 0
end /*k*/ /* [↑] see if 2nd factor is prime or ¬*/
end /*j*/ /* [↑] J is never a multiple of three.*/
```
{{out|output|text= when using the input of: -1 106 }}
(Shown at '''5/6''' size.)
-1 isn't semiprime. 0 isn't semiprime. 1 isn't semiprime. 2 isn't semiprime. 3 isn't semiprime. 4 is semiprime. 5 isn't semiprime. 6 is semiprime. 7 isn't semiprime. 8 isn't semiprime. 9 is semiprime. 10 is semiprime. 11 isn't semiprime. 12 isn't semiprime. 13 isn't semiprime. 14 is semiprime. 15 is semiprime. 16 isn't semiprime. 17 isn't semiprime. 18 isn't semiprime. 19 isn't semiprime. 20 isn't semiprime. 21 is semiprime. 22 is semiprime. 23 isn't semiprime. 24 isn't semiprime. 25 is semiprime. 26 is semiprime. 27 isn't semiprime. 28 isn't semiprime. 29 isn't semiprime. 30 isn't semiprime. 31 isn't semiprime. 32 isn't semiprime. 33 is semiprime. 34 is semiprime. 35 is semiprime. 36 isn't semiprime. 37 isn't semiprime. 38 is semiprime. 39 is semiprime. 40 isn't semiprime. 41 isn't semiprime. 42 isn't semiprime. 43 isn't semiprime. 44 isn't semiprime. 45 isn't semiprime. 46 is semiprime. 47 isn't semiprime. 48 isn't semiprime. 49 is semiprime. 50 isn't semiprime. 51 is semiprime. 52 isn't semiprime. 53 isn't semiprime. 54 isn't semiprime. 55 is semiprime. 56 isn't semiprime. 57 is semiprime. 58 is semiprime. 59 isn't semiprime. 60 isn't semiprime. 61 isn't semiprime. 62 is semiprime. 63 isn't semiprime. 64 isn't semiprime. 65 is semiprime. 66 isn't semiprime. 67 isn't semiprime. 68 isn't semiprime. 69 is semiprime. 70 isn't semiprime. 71 isn't semiprime. 72 isn't semiprime. 73 isn't semiprime. 74 is semiprime. 75 isn't semiprime. 76 isn't semiprime. 77 is semiprime. 78 isn't semiprime. 79 isn't semiprime. 80 isn't semiprime. 81 isn't semiprime. 82 is semiprime. 83 isn't semiprime. 84 isn't semiprime. 85 is semiprime. 86 is semiprime. 87 is semiprime. 88 isn't semiprime. 89 isn't semiprime. 90 isn't semiprime. 91 is semiprime. 92 isn't semiprime. 93 is semiprime. 94 is semiprime. 95 is semiprime. 96 isn't semiprime. 97 isn't semiprime. 98 isn't semiprime. 99 isn't semiprime. 100 isn't semiprime. 101 isn't semiprime. 102 isn't semiprime. 103 isn't semiprime. 104 isn't semiprime. 105 isn't semiprime. 106 is semiprime. found 35 semiprimes. ``` {{out|output|text= when using the input of: 99888111555 99888111600 }} (Shown at '''5/6''' size.)99888111555 isn't semiprime. 99888111556 isn't semiprime. 99888111557 isn't semiprime. 99888111558 isn't semiprime. 99888111559 isn't semiprime. 99888111560 isn't semiprime. 99888111561 isn't semiprime. 99888111562 isn't semiprime. 99888111563 is semiprime. 99888111564 isn't semiprime. 99888111565 isn't semiprime. 99888111566 is semiprime. 99888111567 isn't semiprime. 99888111568 isn't semiprime. 99888111569 is semiprime. 99888111570 isn't semiprime. 99888111571 isn't semiprime. 99888111572 isn't semiprime. 99888111573 isn't semiprime. 99888111574 is semiprime. 99888111575 isn't semiprime. 99888111576 isn't semiprime. 99888111577 isn't semiprime. 99888111578 is semiprime. 99888111579 isn't semiprime. 99888111580 isn't semiprime. 99888111581 isn't semiprime. 99888111582 isn't semiprime. 99888111583 isn't semiprime. 99888111584 isn't semiprime. 99888111585 isn't semiprime. 99888111586 isn't semiprime. 99888111587 isn't semiprime. 99888111588 isn't semiprime. 99888111589 isn't semiprime. 99888111590 isn't semiprime. 99888111591 is semiprime. 99888111592 isn't semiprime. 99888111593 is semiprime. 99888111594 isn't semiprime. 99888111595 isn't semiprime. 99888111596 isn't semiprime. 99888111597 isn't semiprime. 99888111598 isn't semiprime. 99888111599 isn't semiprime. 99888111600 isn't semiprime. found 7 semiprimes. ``` ===version 3, with memoization=== This REXX version is overt 20% faster than version 2 (when in the ''millions'' range). If the 2nd argument ('''top''') is negative (it's absolute value is used), individual numbers in the range aren't shown, but the ''count'' of semiprimes found is shown. It gets its speed increase by the use of memoization of the prime numbers found, an unrolled primality (division) check, and other speed improvements. ```rexx /*REXX program determines if any integer (or a range of integers) is/are semiprime. */ parse arg bot top . /*obtain optional arguments from the CL*/ if bot=='' | bot=="," then bot=random() /*None given? User wants us to guess.*/ if top=='' | top=="," then top=bot /*maybe define a range of numbers. */ tell= bot=>0 & top=>0 /*should results be shown to the term? */ w=max(length(bot), length(top)) /*obtain the maximum width of numbers. */ !.=; !.2=1; !.3=1; !.5=1; !.7=1; !.11=1; !.13=1; !.17=1; !.19=1; !.23=1; !.29=1; !.31=1 numeric digits max(9, w) /*ensure there're enough decimal digits*/ #=0 /*initialize number of semiprimes found*/ do n=abs(bot) to abs(top) /*show results for a range of numbers. */ ?=isSemiPrime(n); #=#+? /*Is N a semiprime?; Maybe bump counter*/ if tell then say right(n,w) right(word("isn't" 'is', ?+1), 6) 'semiprime.' end /*n*/ say if bot\==top then say 'found ' # " semiprimes." exit /*stick a fork in it, we're all done. */ /*──────────────────────────────────────────────────────────────────────────────────────*/ isPrime: procedure expose !.; parse arg x; if x<2 then return 0 /*number too low?*/ if !.x==1 then return 1 /*a known prime. */ if x// 2==0 then return 0; if x//3==0 then return 0 /*÷ by 2;÷by 3?*/ parse var x '' -1 _; if _==5 then return 0 /*last digit a 5?*/ if x// 7==0 then return 0; if x//11==0 then return 0 /*÷ by 7;÷by 11?*/ if x//13==0 then return 0; if x//17==0 then return 0 /*÷ by 13;÷by 17?*/ if x//19==0 then return 0; if x//23==0 then return 0 /*÷ by 19;÷by 23?*/ do j=29 by 6 until j*j>x; if x//j==0 then return 0 /*not a prime. */ if x//(j+2)==0 then return 0 /* " " " */ end /*j*/ !.x=1; return 1 /*indicate that X is a prime number. */ /*──────────────────────────────────────────────────────────────────────────────────────*/ isSemiPrime: procedure expose !.; parse arg x; if x<4 then return 0 do i=2 for 2; if x//i==0 then if isPrime(x%i) then return 1 else return 0 end /*i*/ /* ___ */ do j=5 by 6 until j*j>x /* > √ x ?*/ do k=j by 2 for 2; if x//k==0 then if isPrime(x%k) then return 1 else return 0 end /*k*/ /* [↑] see if 2nd factor is prime or ¬*/ end /*j*/ /* [↑] J is never a multiple of three.*/ return 0 ``` {{out|output|text= is identical to the previous REXX version.}} ## Ring ```ring prime = 1679 decomp(prime) func decomp nr x = "" sum = 0 for i = 1 to nr if isPrime(i) and nr % i = 0 sum = sum + 1 x = x + string(i) + " * " ok if i = nr and sum = 2 x2 = substr(x,1,(len(x)-2)) see string(nr) + " = " + x2 + "is semiprime" + nl but i = nr and sum != 2 see string(nr) + " is not semiprime" + nl ok next func isPrime n if n < 2 return false ok if n < 4 return true ok if n % 2 = 0 and n != 2 return false ok for d = 3 to sqrt(n) step 2 if n % d = 0 return false ok next return true ``` ## Ruby ```ruby require 'prime' # 75.prime_division # Returns the factorization.75 divides by 3 once and by 5 twice => [[3, 1], [5, 2]] class Integer def semi_prime? prime_division.sum(&:last) == 2 end end p 1679.semi_prime? # true p ( 1..100 ).select( &:semi_prime? ) # [4, 6, 9, 10, 14, 15, 21, 22, 25, 26, 33, 34, 35, 38, 39, 46, 49, 51, 55, 57, 58, 62, 65, 69, 74, 77, 82, 85, 86, 87, 91, 93, 94, 95] ``` ## Rustextern crate primal; fn isqrt(n: usize) -> usize { (n as f64).sqrt() as usize } fn is_semiprime(mut n: usize) -> bool { let root = isqrt(n) + 1; let primes1 = primal::Sieve::new(root); let mut count = 0; for i in primes1.primes_from(2).take_while(|&x| x < root) { while n % i == 0 { n /= i; count += 1; } if n == 1 { break; } } if n != 1 { count += 1; } count == 2 } #[test] fn test1() { assert_eq!((2..10).filter(|&n| is_semiprime(n)).count(), 3); } #[test] fn test2() { assert_eq!((2..100).filter(|&n| is_semiprime(n)).count(), 34); } #[test] fn test3() { assert_eq!((2..1_000).filter(|&n| is_semiprime(n)).count(), 299); } #[test] fn test4() { assert_eq!((2..10_000).filter(|&n| is_semiprime(n)).count(), 2_625); } #[test] fn test5() { assert_eq!((2..100_000).filter(|&n| is_semiprime(n)).count(), 23_378); } #[test] fn test6() { assert_eq!((2..1_000_000).filter(|&n| is_semiprime(n)).count(), 210_035); } ``` {{out}} ```txt running 6 tests test test1 ... ok test test2 ... ok test test3 ... ok test test4 ... ok test test5 ... ok test test6 ... ok test result: ok. 6 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out ``` ## Scala {{works with|Scala 2.9.1}} ```Scala object Semiprime extends App { def isSP(n: Int): Boolean = { var nf: Int = 0 var l = n for (i <- 2 to l/2) { while (l % i == 0) { if (nf == 2) return false nf +=1 l /= i } } nf == 2 } (2 to 100) filter {isSP(_) == true} foreach {i => print("%d ".format(i))} println 1675 to 1681 foreach {i => println(i+" -> "+isSP(i))} } ``` {{out}} ```txt 4 6 9 10 14 15 21 22 25 26 33 34 35 38 39 46 49 51 55 57 58 62 65 69 74 77 82 85 86 87 91 93 94 95 1675 -> false 1676 -> false 1677 -> false 1678 -> true 1679 -> true 1680 -> false 1681 -> true ``` ## Seed7 ```seed7 $ include "seed7_05.s7i"; const func boolean: semiPrime (in var integer: n) is func result var boolean: isSemiPrime is TRUE; local var integer: p is 2; var integer: f is 0; begin while f < 2 and p**2 <= n do while n rem p = 0 do n := n div p; incr(f); end while; incr(p); end while; isSemiPrime := f + ord(n > 1) = 2; end func; const proc: main is func local var integer: v is 0; begin for v range 1675 to 1680 do writeln(v <& " -> " <& semiPrime(v)); end for; end func; ``` {{out}} ```txt 1675 -> FALSE 1676 -> FALSE 1677 -> FALSE 1678 -> TRUE 1679 -> TRUE 1680 -> FALSE ``` ## Sidef Built-in: ```ruby say is_semiprime(2**128 + 1) #=> true say is_semiprime(2**256 - 1) #=> false ``` User-defined function, with trial division up to a given bound '''B''': ```ruby func is_semiprime(n, B=1e4) { with (n.trial_factor(B)) { |f| return false if (f.len > 2) return f.all { .is_prime } if (f.len == 2) } n.factor.len == 2 } say [2,4,99,100,1679,32768,1234567,9876543,900660121].grep(is_semiprime) ``` {{out}} ```txt [4, 1679, 1234567, 900660121] ``` ## Swift ```swift import Foundation func primes(n: Int) -> AnyGenerator { var (seive, i) = ([Int](0.. Bool { let g = primes(n) while let first = g.next() { if n % first == 0 { if first * first == n { return true } else { while let second = g.next() { if first * second == n { return true } } } } } return false } ``` ## Tcl {{tcllib|math::numtheory}} ```tcl package require math::numtheory proc isSemiprime n { if {!($n & 1)} { return [::math::numtheory::isprime [expr {$n >> 1}]] } for {set i 3} {$i*$i < $n} {incr i 2} { if {$n / $i * $i != $n && [::math::numtheory::isprime $i]} { if {[::math::numtheory::isprime [expr {$n/$i}]]} { return 1 } } } return 0 } for {set n 1675} {$n <= 1680} {incr n} { puts -nonewline "$n is ... " if {[isSemiprime $n]} { puts "a semiprime" } else { puts "NOT a semiprime" } } ``` {{out}} ```txt 1675 is ... a semiprime 1676 is ... NOT a semiprime 1677 is ... a semiprime 1678 is ... a semiprime 1679 is ... a semiprime 1680 is ... NOT a semiprime ``` ## zkl {{trans|C}} ```zkl fcn semiprime(n){ reg f = 0; p:=2; while(f < 2 and p*p <= n){ while(0 == n % p){ n /= p; f+=1; } p+=1; } return(f + (n > 1) == 2); } ``` {{out}} ```txt [1675 .. 1681].filter(semiprime).println(); L(1678,1679,1681) ```