-2 bytes thanks to dingledooper with a different way to detect if k-2
is a prime which works with k=2
.
Uses Wilson's theorem for the primality tests and the fact that \$p\$, \$p+1\$ and \$p+2\$ are coprime for most primes \$p\$.
P=k=q=1
exec"if P%k:print`k`+'*'[k<3:P%(k+2)|q/k];q=k+2\nP*=k*k;k+=1\n"*input()
Try it online!
The output includes the input if it is prime, but this is fine since all testcases are composite.
How?
We use the following result of Wilson's theorem:
$$
(k-1)!^2 \operatorname{mod} k =
\begin{cases}
1 & \text{if $k$ is prime}\\
0 & \text{otherwise.}
\end{cases}
$$
In the code P
is used to keep track of \$(k-1)!^2\$ and P%k
tests if k
is a prime.
If this is the case, we print the output and update q
to k+2
.
If k==q
at the print
statement, we know that k-2
was a prime and k
is a twin prime.
P%(k+2)
tests if k+2
is a prime number. If we would use the exact same prime test as before, this would be P*k*k*(k+1)*(k+1)%(k+2)
, but with our assumption that \$k\$, \$k+1\$ and \$k+2\$ are coprime for prime \$k\$, this gives the same result.
The assumption doesn't hold for k=2
, but this is handled separately with '*'[k<3:]
, which results in the empty string if k<3
.