September 2017 Update

This commit is contained in:
Ingy döt Net 2017-09-23 10:01:46 +02:00
parent bba7bfd280
commit ba8067c3b7
14570 changed files with 153136 additions and 63871 deletions

View file

@ -1,41 +1,49 @@
import Data.List (sort)
import Control.Arrow ((&&&))
primes = 2:filter isPrime [3,5..] where
isPrime n = f n primes where
f n (p:ps)
| p*p > n = True
| n`mod`p == 0 = False
| otherwise = f n ps
primeFactors n = f n primes where
f n (p:ps)
| p*p > n = if n == 1 then [] else [(n,1)]
| n`mod`p == 0 = (p,e):f res ps
| otherwise = f n ps
where (e,res) = ppower (n`div`p) p 1
ppower n p e
| n`mod`p /= 0 = (e,n)
| otherwise = ppower (n`div`p) p (e+1)
factors n = comb (primeFactors n) where
comb [] = [1]
comb ((p,e):others) = [a*b | b<-map (p^) [0 .. e], a<-comb others]
ndigit 0 = 0
ndigit n = 1 + ndigit (n`div`10)
-- VAMPIRE NUMBERS ------------------------------------------------------------
vampires :: [Int]
vampires = filter ((0 <) . length . fangs) [1 ..]
fangs :: Int -> [(Int, Int)]
fangs n
| odd w = []
| otherwise = map (\x->(x,n`div`x)) $ filter isfang (factors n) where
isfang x = x > xmin && x < y && y < ymax && -- same length
((x`div`10)/=0 || (y`div`10)/=0) && -- not zero-ended
sort (show n) == sort ((show x) ++ (show y)) -- same digits
where y = n`div`x
w = ndigit n
xmin = 10^(w`div`2-1)
ymax = 10^(w`div`2)
| odd w = []
| otherwise = ((,) <*> quot n) <$> filter isfang (integerFactors n)
where
ndigit :: Int -> Int
ndigit 0 = 0
ndigit n = 1 + ndigit (quot n 10)
w = ndigit n
xmin = 10 ^ (quot w 2 - 1)
xmax = xmin * 10
isfang x =
x > xmin &&
x < y &&
y < xmax && -- same length
(quot x 10 /= 0 || quot y 10 /= 0) && -- not zero-ended
sort (show n) == sort (show x ++ show y)
where
y = quot n x
vampires = filter ((0<).length.fangs) [1..]
-- FACTORS --------------------------------------------------------------------
integerFactors :: Int -> [Int]
integerFactors n
| n < 1 = []
| otherwise =
lows ++
(quot n <$>
(if intSquared == n -- A perfect square,
then tail -- and cofactor of square root would be redundant.
else id)
(reverse lows))
where
(intSquared, lows) =
(^ 2) &&& (filter ((0 ==) . rem n) . enumFromTo 1) $
floor (sqrt $ fromIntegral n)
main = mapM (\n->print (n,fangs n)) $
((take 25 vampires) ++ [16758243290880, 24959017348650, 14593825548650])
-- TEST -----------------------------------------------------------------------
main :: IO [()]
main =
mapM
(print . ((,) <*>) fangs)
(take 25 vampires ++ [16758243290880, 24959017348650, 14593825548650])

View file

@ -0,0 +1,96 @@
// version 1.1
data class Fangs(val fang1: Long = 0L, val fang2: Long = 0L)
fun pow10(n: Int): Long = when {
n < 0 -> throw IllegalArgumentException("Can't be negative")
else -> {
var pow = 1L
for (i in 1..n) pow *= 10L
pow
}
}
fun countDigits(n: Long): Int = when {
n < 0L -> throw IllegalArgumentException("Can't be negative")
n == 0L -> 1
else -> {
var count = 0
var nn = n
while (nn > 0L) {
count++
nn /= 10L
}
count
}
}
fun hasTrailingZero(n: Long): Boolean = when {
n < 0L -> throw IllegalArgumentException("Can't be negative")
else -> n % 10L == 0L
}
fun sortedString(s: String): String {
val ca = s.toCharArray()
ca.sort()
return String(ca)
}
fun isVampiric(n: Long, fl: MutableList<Fangs>): Boolean {
if (n < 0L) return false
val len = countDigits(n)
if (len % 2L == 1L) return false
val hlen = len / 2
val first = pow10(hlen - 1)
val last = 10L * first
var j: Long
var cd: Int
val ss = sortedString(n.toString())
for (i in first until last) {
if (n % i != 0L) continue
j = n / i
if (j < i) return fl.size > 0
cd = countDigits(j)
if (cd > hlen) continue
if (cd < hlen) return fl.size > 0
if (ss != sortedString(i.toString() + j.toString())) continue
if (!(hasTrailingZero(i) && hasTrailingZero(j))) {
fl.add(Fangs(i, j))
}
}
return fl.size > 0
}
fun showFangs(fangsList: MutableList<Fangs>): String {
var s = ""
for ((fang1, fang2) in fangsList) {
s += " = $fang1 x $fang2"
}
return s
}
fun main(args: Array<String>) {
println("The first 25 vampire numbers and their fangs are:")
var count = 0
var n: Long = 0
val fl = mutableListOf<Fangs>()
while (true) {
if (isVampiric(n, fl)) {
count++
println("${"%2d".format(count)} : $n\t${showFangs(fl)}")
fl.clear()
if (count == 25) break
}
n++
}
println()
val va = longArrayOf(16758243290880L, 24959017348650L, 14593825548650L)
for (v in va) {
if (isVampiric(v, fl)) {
println("$v\t${showFangs(fl)}")
fl.clear()
} else {
println("$v\t = not vampiric")
}
}
}

View file

@ -0,0 +1,62 @@
EnableExplicit
DisableDebugger
Macro CheckVamp(CheckNum)
c=0 : i=CheckNum : Print(~"\nCheck number: "+Str(i)+~"\n")
Gosub VampireLoop : If c=0 : Print(Str(i)+" is not vampiric.") : EndIf : PrintN("")
EndMacro
Procedure.i Factor(number.i,counter.i)
If number>0 And number>=counter*counter And number%counter=0
ProcedureReturn counter
EndIf
ProcedureReturn 0
EndProcedure
Procedure.b IsVampire(f1.i,f2.i)
Define a.s=Str(f1*f2),
b.s=Str(f1),
c.s=Str(f2),
d.s=b+c,
i.i
If Len(a)=Len(d) And Len(b)=Len(c)
While Len(a)
i=FindString(d,Left(a,1))
If i
a=Mid(a,2)
d=RemoveString(d,Mid(d,i,1),#PB_String_NoCase,i,1)
Else
ProcedureReturn #False
EndIf
Wend
ProcedureReturn Bool(Len(d)=0)
EndIf
ProcedureReturn #False
EndProcedure
OpenConsole("Vampire number")
Define i.i,
j.i,
m.i,
c.i=0
PrintN("The first 25 Vampire numbers...")
While c<25 : i+1 : Gosub VampireLoop : Wend
PrintN("")
CheckVamp(16758243290880) : CheckVamp(24959017348650) : CheckVamp(14593825548650)
Input()
End
VampireLoop:
For j=1 To Int(Sqr(i))
If Factor(i,j)>0
m=i/j
Else
Continue
EndIf
If IsVampire(m,j)
c+1
PrintN(RSet(Str(c),3," ")+". "+RSet(Str(i),10," ")+": ["+Str(j)+", "+Str(m)+"]")
EndIf
Next
Return

View file

@ -1,46 +1,42 @@
/*REXX pgm displays N vampire numbers, or verifies if a # is vampiric.*/
numeric digits 20 /*be able to handle large numbers*/
parse arg N .; if N=='' then N=25 /*No arg? Then use the default. */
!.0=1260; !.1=11453481; !.2=115672; !.3=124483; !.4=105264 /*lowest#,dig*/
!.5=1395; !.6=126846; !.7=1827; !.8=110758; !.9=156289 /*lowest#,dig*/
#=0 /*number of vampire numbers found*/
if N>0 then do j=1260 until # >= N /*search until N vampire #s found*/
if length(j)//2 then do; j=j*10-1; iterate; end /*adjust J*/
_=right(j,1) /*obtain the right-most J digit.*/
if j<!._ then iterate /*is # tenable based on last dig?*/
f=vampire(j) /*get possible fangs for J. */
if f=='' then iterate /*Are fangs null? Yes, ¬vampire.*/
#=#+1 /*bump the vampire count, Vlad. */
say 'vampire number' right(#,length(N)) "is: " j', fangs=' f
end /*j*/ /* [↑] process range of numbers.*/
else do; N=abs(N) /* [↓] process a particular num.*/
f=vampire(N) /*get possible fangs for abs(N).*/
if f=='' then say N " isn't a vampire number."
else say N " is a vampire number, fangs=" f
/*REXX program displays N vampire numbers, or verifies if a number is vampiric. */
numeric digits 20 /*be able to handle gihugic numbers. */
parse arg N .; if N=='' | N=="," then N=25 /*Not specified? Then use the default.*/
!.0=1260; !.1=11453481; !.2=115672; !.3=124483; !.4=105264 /*lowest #, dig.*/
!.5=1395; !.6=126846; !.7=1827; !.8=110758; !.9=156289 /* " " " */
#=0 /*num. of vampire numbers found, so far*/
if N>0 then do j=1260 until # >= N /*search until N vampire numbers found.*/
if length(j) // 2 then do; j=j*10 - 1; iterate; end /*adjust J*/
_=right(J,1); if j<!._ then iterate /*is number tenable based on last dig? */
f=vampire(j); if f=='' then iterate /*Are fangs null? Yes, not vampire. */
#=#+1 /*bump the vampire count, Vlad. */
say 'vampire number' right(#,length(N)) "is: " j', fangs=' f
end /*j*/ /* [↑] process a range of numbers. */
else do; N=abs(N); f=vampire(N) /* [↓] process one number; get fangs.*/
if f=='' then say N " isn't a vampire number."
else say N " is a vampire number, fangs=" f
end
exit /*stick a fork in it, we're done.*/
/*──────────────────────────────────VAMPIRE subroutine──────────────────*/
vampire: procedure; parse arg ?,,$. !!; L=length(?); w=L%2
if L//2 then return !! /*Odd length? Then not vampire.*/
do k=1 for L; _=substr(?,k,1); $._=$._ || _; end /*k*/
bot=; do m=0 for 10; bot=bot || $.m; end /*m*/
top=left(reverse(bot),w); bot=left(bot,w) /*determine limits of search*/
if ?//2 then inc=2 /*if ? is odd, set INC to 2.*/
else inc=1 /*··otherwise, set INC to 1.*/
start=max(bot,10**(w-1)); if inc=2 then if start//2==0 then start=start+1
/* [↑] odd START if odd INC*/
do d=start to min(top, 10**w-1) by inc
if ?//d\==0 then iterate
if verify(d,?)\==0 then iterate
q=?%d; if d>q then iterate
if q*d//9\==(q+d)//9 then iterate /*modulo 9 congruence.*/
if verify(q,?)\==0 then iterate
if right(q,1)==0 then if right(d,1)==0 then iterate
if length(q)\==w then iterate
dq=d || q; t=?
do i=1 for L; p=pos(substr(dq,i,1), t)
if p==0 then iterate d; t=delstr(t,p,1)
end /*i*/
!!=!! '['d""q']'
end /*d*/
return !!
exit /*stick a fork in it, we're all done. */
/*──────────────────────────────────────────────────────────────────────────────────────*/
vampire: procedure; parse arg ?,, $. !! bot; L=length(?); if L//2 then return !!
w=L%2 /* [↑] L an odd length? Then ¬vampire*/
do k=1 for L; _=substr(?,k,1); $._=$._ || _; end /*k*/
do m=0 for 10; bot=bot || $.m; end /*m*/
top=left( reverse(bot), w); bot=left(bot, w) /*determine limits of search*/
inc=?//2 + 1 /*? is odd? INC=2. No? INC=1*/
start=max(bot, 10**(w-1)); if inc=2 then if start//2==0 then start=start+1
/* [↑] odd START if odd INC*/
do d=start to min(top, 10**w-1) by inc
if ?//d\==0 then iterate
if verify(d, ?) \==0 then iterate
q=?%d; if d>q then iterate
if q*d//9\==(q+d)//9 then iterate /*modulo 9 congruence test. */
if verify(q, ?) \==0 then iterate
if right(q, 1) ==0 then if right(d, 1)==0 then iterate
if length(q)\==w then iterate
dq=d || q; t=?
do i=1 for L; p=pos( substr(dq, i, 1), t)
if p==0 then iterate d; t=delstr(t, p, 1)
end /*i*/
!!=!! '['d""q']'
end /*d*/
return !!

View file

@ -0,0 +1,13 @@
fcn fangs(N){ //-->if Vampire number: (N,(a,b,c,...)), where a*x==N
var [const] tens=[0 .. 18].pump(List,(10.0).pow,"toInt");
(half:=N.numDigits) : if (_.isOdd) return(T);;
half/=2; digits:=N.toString().sort();
lo:=tens[half-1].max((N+tens[half])/(tens[half]));
hi:=(N/lo).min(N.toFloat().sqrt());
fs:=[lo .. hi].filter('wrap(n){
N%n==0 and (n%10!=0 or (N/n)%10!=0) and
(n.toString()+(N/n).toString()).sort()==digits
});
fs and T(N,fs) or T;
}

View file

@ -0,0 +1,9 @@
fcn vampiric(fangs,n=Void){
if(not fangs) return(n,"Not a Vampire number");
v:=fangs[0]; T(v,fangs[1].apply('wrap(n){T(n,v/n)})) }
T(16758243290880, 24959017348650, 14593825548650)
.pump(Console.println,fcn(n){"%d: %s".fmt(vampiric(fangs(n),n).xplode())});
(0).walker(*).tweak(fangs).filter(26)
.pump(Console.println,vampiric);