#!/usr/local/bin/bc -l digits.bc
### Digits-Misc.BC - Treat numbers as strings of digits II
## Functions of interest but questionable worth
# Workhorse function - use POSIX scope to check
# . 'base' parameter of many functions here
define base_check_misc_() {
if(bijective)print "Bijective mode not supported by this function.\n"
if(base<2){
if(base<=-2){
print "Negative bases not currently supported; "
} else if(base==-1||base==0||base==1) {
print "Nonsense base: ",base,"; "
}
print "Using ibase instead.\n"
base=ibase
}
}
# Product of each digit with one added, less 1
# e.g. 235 -> (2+1)(3+1)(5+1)-1 = 3*4*6 - 1 = 71 in base ten
define digit_product1(base,x) {
auto os,t;
if(x<0)return digit_product1(base,-x);
os=scale;scale=0;base/=1;x/=1
.=base_check_misc_()
t=1;while(x){t*=1+(x%base);x/=base}
scale=os;return(t-1)
}
# Product of each digit's corresponding odd numbers through the relation
# digit -> 2*digit + 1, then the result is passed through the inverse relation x -> (x-1)/2
# e.g. 13462 -> ( (2*1+1)(2*3+1)(2*4+1)(2*6+1)(2*2+1)-1 )/2 = (3*7*9*13*5 - 1)/2 = 6142
define digit_product2(base,x) {
auto os,t;
if(x<0)return digit_product2(base,-x);
os=scale;scale=0;base/=1;x/=1
.=base_check_misc_()
t=1;while(x){t*=1+2*(x%base);x/=base}
t=(t-1)/2
scale=os;return(t)
}
## Swap digit pairs
define sdp(base,x) {
auto os,b2,t,nx,dd,dl,dr,pw;
if(x<0)return sdp(base,-x)
.=base_check_misc_()
os=scale;scale=0;base/=1
b2=base*base
nx=x/1
if(scale(x)&&x!=nx){
pw=A^os;for(t=1;t<=pw;t*=b2){}
nx=(x*t)/1
scale=os;return sdp(base,nx)/t
}
x=nx;pw=1
for(t=0;x;x=nx){dd=x-(nx=x/b2)*b2;dr=dd-(dl=dd/base)*base;t+=pw*(dr*base+dl);pw*=b2;x=nx}
scale=os;return t
}
## Palindromes
# Determine if x is a negapalindrome (type 1) in the given base
# - an NP is any number whose opposing pairs of digits,
# (counted in from either end) sum to one less than the base
# e.g. 147258 is an NP(1) in base ten since 1+8 = 4+5 = 7+2 = 9 = ten - 1
define is_negapalindrome(base,x) {
auto os
os=scale;scale=0;base/=1;x/=1
.=base_check_misc_()
# divisibility by base-1 is a necessary condition for [P]NP(1)s in even bases
# divisibility by (base-1)/2 is a necessary condition for [P]NP(1)s in odd bases
if(x%((base-1)/(1+base%2))!=0){scale=os;return 0}
if(x<0)x=-x
x += reverse(base,x)+1
if(x a single digit NP(1), which is invalid for even bases
r=base^digits(base,x)
x=x*r+reverse(base,r*base-1-x)/base
}
scale=os;return s*x
}
define unmap_negapalindrome(base, x) {
auto os,r,s
os=scale;scale=0
s=1;if(x<0)x*=(s=-1)
.=base_check_misc_()
if(base%2){
r=base^((digits(base,x)+1)/2)
x=x/r+r/base-1
} else {
r=base^(digits(base,x)/2)
x=x/r-1
}
scale=os;return s*x
}
## To do (one day): map_ functions for remaining NPs and PNPs
## Calculator segments
# Return the number of segments of a 7-segment calculator display that
# are required to display the value of x in the given base.
# Supports up to base 36; Some calculators may have a different number
# of segments per number than given here.
define calcsegments(base,x) {
auto os,oib,s[],t;
oib=ibase;ibase=A
s[ 0]=s[ 6]=s[ 9]=s[10]=s[32]=6
s[ 1]=s[27]=2
s[ 2]=s[ 3]=s[ 5]=s[11]=s[13]=s[14]=s[16]=s[25]=s[26]=s[31]=s[34]=5
s[ 4]=s[12]=s[15]=s[17]=s[20]=s[24]=s[28]=s[29]=s[35]=4
s[ 7]=s[19]=s[21]=s[22]=s[23]=s[30]=s[33]=3
s[ 8]=7
s[18]=1
ibase=oib
os=scale;scale=0;x/=1
t=0;if(x<0){t=1;x=-x}
if(x==0){scale=os;return s[0]}
if(2>base||base>6*6){
print "calcsegments: only bases 2 to 36 (decimal) supported\n";
base=A
}
while(x){t+=s[x%base];x/=base}
scale=os;return t
}
## Miscellaneous
# The base number created by appending all base numbers
# from 1 to x, e.g. in base ten: 1, 12, 123, ..., 123456789101112, etc.
define append_all(base,x) {
auto a,i,m,l,os;
os=scale;scale=0;base/=1;x/=1
.=base_check_misc_()
if(x<=0)return(0);
m=1;while(x){l=m;m*=base;for(i=l;i0){.=d[x%base]++;x/=base}
for(i=base-1;i>=0;i--)if(d[i])for(j=0;j0){.=d[x%base]++;x/=base}
for(i=1;id){n=d}
s=1;if(-n>=m){s=-1;base=-n}else{base=m}
for(i=0;(d=d__[i])=0;i++)x=x*base+d
if(d__[i]!=s*base){print "join_digits: unexpected element in array\n";scale=os;return x/s}
scale=os+5;x+=5*A^(-1-os)
for(p=1/base;p&&(d=d__[++i])=0;p/=base)x+=d*p
if(d__[i]!=-1)print "join_digits: unexpected element in array\n";
scale=os;return x/s
}
## Pandigital Index
# pdhi(x) - Pan Digital Halving Index
# Returns how many times x must be divided by 2 before
# the result contains all digits from 0 to 9 (if ibase = 10).
# e.g. 3339 -> 1669.5 -> 834.75 -> 417.375 ->
# 208.6875 -> 104.34375 -> 52.171875 ->
# 26.0859375 -> 13.04296875, i.e. 8 times
# Uses ibase as the base for divisions (usually 10)
define pdhi(x) {
auto d[],xi,xf,c,r,pdhi,lim,i;
if(x==0){print "pdhi: Infinity\n";return A^scale-1}
if(x<0)x=-x
c=1;pdhi=-1;lim=int(A/ibase+3)*scale
while(c){
pdhi+=1
xi=int(x);xf=x-xi
while(xi){
r=int(xi/ibase)
d[xi-ibase*r]=1
xi=r
}
for(i=lim ; i && xf ; i--){
#while(xf){
xf*=ibase
r=int(xf)
d[r]=1
xf-=r
}
c=ibase
for(r=0;r 1669.5 -> 834.75 -> 417.375 ->
# 208.6875 -> 104.34375 -> 52.171875 ->
# 26.0859375 -> 13.04296875, i.e. 8 times
# Uses ibase as the base for divisions (usually 10)
define pdmi(x,m) {
auto d[],xi,xf,c,r,pdmi,lim,i;
if(x==0){print "pdmi: Infinity\n";return A^scale-1}
if(x<0)x=-x
c=1;pdmi=-1;lim=int(A/ibase+3)*scale
while(c){
pdmi+=1
xi=int(x);xf=x-xi
while(xi){
r=int(xi/ibase)
d[xi-ibase*r]=1
xi=r
}
for(i=lim ; i && xf ; i--){
#while(xf){
xf*=ibase
r=int(xf)
d[r]=1
xf-=r
}
c=ibase
for(r=0;r