536 lines
No EOL
14 KiB
JavaScript
536 lines
No EOL
14 KiB
JavaScript
function span(first, n=10) {
|
||
return [...new Array(n)].map((_,i) => first.slice(0,first.length-1)+String.fromCharCode(first.charCodeAt(first.length-1) + i));
|
||
}
|
||
|
||
function positional_unicode_span(name, zero, base=10n, extra) {
|
||
// Make a function to render a positional number system whose digits are in a contiguous span of unicode code points.
|
||
return Object.assign({
|
||
name,
|
||
fn: (n) => {
|
||
let o = '';
|
||
if(n==0n) {
|
||
return zero;
|
||
}
|
||
while(n) {
|
||
const d = n % base;
|
||
n = (n - d)/base;
|
||
const c = zero.slice(0,zero.length-1) + String.fromCharCode(zero.charCodeAt(zero.length-1) + Number(d));
|
||
o = c + o;
|
||
}
|
||
return o;
|
||
}
|
||
}, extra || {})
|
||
}
|
||
|
||
function positional_symbols(name, symbols) {
|
||
// Make a function to render a positional number system whose digits are drawn from the given string.
|
||
return {
|
||
name,
|
||
fn: (n) => {
|
||
let o = '';
|
||
const base = BigInt(symbols.length);
|
||
if(n == 0n) {
|
||
return symbols[0];
|
||
}
|
||
|
||
while(n) {
|
||
const d = n % base;
|
||
n = (n - d)/base;
|
||
o = symbols[d] + o;
|
||
}
|
||
return o;
|
||
}
|
||
};
|
||
}
|
||
|
||
function concatenative(power_lists, base=10n) {
|
||
return function(n) {
|
||
if(n==0n) {
|
||
return '';
|
||
}
|
||
|
||
let o = '';
|
||
for(let symbols of power_lists) {
|
||
|
||
const r = n % 10n;
|
||
if(r > symbols.length) {
|
||
return '???';
|
||
|
||
}
|
||
if(r > 0n) {
|
||
o = symbols[Number(r)-1] + o;
|
||
}
|
||
n = (n-r) / 10n;
|
||
}
|
||
if(n) {
|
||
return '???';
|
||
}
|
||
return o;
|
||
}
|
||
}
|
||
|
||
function chinese_system(zero,units, powers_of_ten, powers_of_myriad) {
|
||
return (n => {
|
||
if(n==0n) {
|
||
return zero;
|
||
}
|
||
|
||
let o = '';
|
||
for(let m of powers_of_myriad) {
|
||
if(n % 10000n == 0n) {
|
||
n = n / 10000n;
|
||
continue;
|
||
}
|
||
o = m + o;
|
||
const u = n % 10n;
|
||
n = (n-u) / 10n;
|
||
o = (u > 1 || m=='' ? units[u] : '') + o;
|
||
for(let pow of powers_of_ten) {
|
||
if(n==0n) {
|
||
break;
|
||
}
|
||
const d = n % 10n;
|
||
n = (n-d) / 10n;
|
||
if(d > 0n) {
|
||
o = (d>1 ? units[d] : '') + pow + o;
|
||
}
|
||
}
|
||
}
|
||
if(n) {
|
||
return '???';
|
||
}
|
||
return o;
|
||
})
|
||
}
|
||
|
||
const systems = {
|
||
cuneiform: {
|
||
name: 'Cuneiform',
|
||
fn: (n) => {
|
||
const tens = [ "", "𒌋", "𒎙", "𒌍", "𒐏", "𒐐" ];
|
||
const ones = [ "", "𒐕", "𒐖", "𒐗", "𒐘", "𒐙", "𒐚", "𒐛", "𒐜", "𒐝" ];
|
||
|
||
let bits = [];
|
||
while(n) {
|
||
const u = n%10n;
|
||
n = (n-u)/10n;
|
||
const t = n % 6n;
|
||
n = (n-t)/6n;
|
||
bits.splice(0,0,tens[t] + ones[u]);
|
||
}
|
||
return bits.join('\u{3000}');
|
||
}
|
||
},
|
||
|
||
arabic: positional_unicode_span('Eastern Arabic', '٠'),
|
||
|
||
roman: {
|
||
name: 'Roman',
|
||
fn: concatenative([
|
||
['Ⅰ', 'Ⅱ', 'Ⅲ', 'Ⅳ', 'Ⅴ', 'Ⅵ', 'Ⅶ', 'Ⅷ', 'Ⅸ'],
|
||
['Ⅹ', 'ⅩⅩ', 'ⅩⅩⅩ', 'ⅩⅬ', 'Ⅼ', 'ⅬⅩ', 'ⅬⅩⅩ', 'ⅬⅩⅩⅩ', 'ⅩⅭ'],
|
||
['Ⅽ', 'ⅭⅭ', 'ⅭⅭⅭ', 'ⅭⅮ', 'Ⅾ', 'ⅮⅭ', 'ⅮⅭⅭ', 'ⅮⅭⅭⅭ', 'ⅭⅯ' ],
|
||
['Ⅿ', 'ⅯⅯ', 'ⅯⅯⅯ']
|
||
])
|
||
},
|
||
|
||
hieratic: {
|
||
name: 'Egyptian hieroglyphs',
|
||
fn: concatenative([
|
||
['', '𓏺', '𓏻', '𓏼', '𓏽', '𓏾', '𓏿', '𓐀', '𓐁', '𓐂'],
|
||
span('𓎆'),
|
||
span('𓍢'),
|
||
span('𓆼'),
|
||
span('𓂭'),
|
||
['𓆐', '𓆐𓆐', '𓆐𓆐𓆐', '𓆐𓆐𓆐𓆐', '𓆐𓆐𓆐𓆐𓆐', '𓆐𓆐𓆐𓆐𓆐𓆐', '𓆐𓆐𓆐𓆐𓆐𓆐𓆐', '𓆐𓆐𓆐𓆐𓆐𓆐𓆐𓆐', '𓆐𓆐𓆐𓆐𓆐𓆐𓆐𓆐𓆐'],
|
||
['𓁨', '𓁨𓁨', '𓁨𓁨𓁨', '𓁨𓁨𓁨𓁨', '𓁨𓁨𓁨𓁨𓁨', '𓁨𓁨𓁨𓁨𓁨𓁨', '𓁨𓁨𓁨𓁨𓁨𓁨𓁨', '𓁨𓁨𓁨𓁨𓁨𓁨𓁨𓁨', '𓁨𓁨𓁨𓁨𓁨𓁨𓁨𓁨𓁨']
|
||
])
|
||
},
|
||
|
||
aegean: {
|
||
name: 'Aegean',
|
||
fn: concatenative([
|
||
span('𐄇'),
|
||
span('𐄐'),
|
||
span('𐄙'),
|
||
span('𐄢'),
|
||
span('𐄫'),
|
||
|
||
])
|
||
},
|
||
|
||
hebrew: {
|
||
name: 'Hebrew',
|
||
fn: (n) => {
|
||
if(n >= 10000n) {
|
||
return '???';
|
||
}
|
||
const ones = [ "א", "ב", "ג", "ד", "ה", "ו", "ז", "ח", "ט" ];
|
||
const tens = [ "י", "ך", "ל", "ם", "ן", "ס", "ע", "ף", "ץ" ];
|
||
const hundreds = [ "ק", "ר", "ש", "ת", "תק", "תר", "תש", "תתק", "תתר" ];
|
||
const thousands = [`א׳`,`ב׳`,`אב׳`,`בב׳`,`ה׳`,`אה׳`,`בה׳`,`אה׳`,`בבה׳`];
|
||
if(n==0n) {
|
||
return '';
|
||
}
|
||
|
||
let o = '';
|
||
for(let symbols of [ones,tens,hundreds,thousands]) {
|
||
console.log(symbols, n);
|
||
if(n==0n) {
|
||
break;
|
||
}
|
||
const d = n % 10n;
|
||
n = (n-d) / 10n;
|
||
if(d > 0n) {
|
||
o = symbols[Number(d)-1] + o;
|
||
}
|
||
}
|
||
return o;
|
||
}
|
||
},
|
||
|
||
greek: {
|
||
name: 'Greek',
|
||
fn: concatenative([
|
||
["Αʹ", "Βʹ", "Γʹ", "Δʹ", "Εʹ", "Ϛʹ", "Ζʹ", "Ηʹ", "Θʹ" ],
|
||
["Ιʹ", "Κʹ", "Λʹ", "Μʹ", "Νʹ", "Ξʹ", "Οʹ", "Πʹ", "Ϟʹ"],
|
||
[ "Ρʹ", "Σʹ", "Τʹ", "Υʹ", "Φʹ", "Χʹ", "Ψʹ", "Ωʹ", "Ϡʹ" ],
|
||
[ "͵Α", "͵Β", ",Γ", "͵Δ", "͵Ε", "͵Ϛ͵ΣΤ", "͵Ζ", "͵Η", "͵Θ" ],
|
||
[ "͵Ι", "͵Κ", "͵Λ", "͵Μ", "͵Ν", "͵Ξ", "͵Ο", "͵Π", "͵Ϟ" ],
|
||
[ "͵Ρ", "͵Σ", "͵Τ", "͵Υ", "͵Φ", "͵Χ", "͵Ψ", "͵Ω", "͵Ϡ" ]
|
||
])
|
||
},
|
||
|
||
chinese: {
|
||
name: 'Chinese',
|
||
fn: chinese_system(
|
||
'〇',
|
||
[ '', '一', '二', '三', '四', '五', '六', '七', '八', '九' ],
|
||
[ '十', '百', '千' ],
|
||
[ '', '万', '亿', '兆', '京', '垓', '秭', '穰', '沟', '涧', '正', '载' ]
|
||
)
|
||
},
|
||
|
||
counting_rod_horizontal: positional_symbols('Counting rod (horizontal)', ['〇'].concat(span('𝍠',9))),
|
||
|
||
counting_rod_vertical: positional_symbols('Counting rod (vertical)', ['〇'].concat(span('𝍩',9)), 10n, {orientation: 'vertical-lr'}),
|
||
|
||
suzhou: {
|
||
name: 'Suzhou',
|
||
fn: (n) => {
|
||
const zero = '〇';
|
||
|
||
if(n==0n) {
|
||
return zero;
|
||
}
|
||
|
||
let o = '';
|
||
while(n) {
|
||
const d = n % 10n;
|
||
n = (n - d) / 10n;
|
||
o = (d==0n ? zero : String.fromCharCode(0x3020 + Number(d))) + o;
|
||
}
|
||
|
||
return o;
|
||
}
|
||
},
|
||
|
||
ethiopic: {
|
||
name: 'Ethiopic',
|
||
fn: concatenative([
|
||
span('፩',9),
|
||
span('፲',9),
|
||
span('፩',9).map(x => x +'፻'),
|
||
span('፲',9).map(x => x +'፻'),
|
||
span('፩',9).map(x => x +'፼'),
|
||
span('፲',9).map(x => x +'፼'),
|
||
])
|
||
},
|
||
|
||
kharosthi: {
|
||
name: 'Kharosthi',
|
||
fn: (n) => {
|
||
const ones = [ "𐩀", "𐩁", "𐩂", "𐩃", "𐩃𐩀", "𐩃𐩁", "𐩃𐩂", "𐩃𐩃", "𐩃𐩃𐩀", "𐩃𐩃𐩁" ];
|
||
const tens = ["𐩄","𐩅","𐩅𐩄","𐩅𐩅","𐩅𐩅𐩄","𐩅𐩅𐩅","𐩅𐩅𐩅𐩄","𐩅𐩅𐩅𐩅","𐩅𐩅𐩅𐩅𐩄"];
|
||
if(n == 0) {
|
||
return '';
|
||
}
|
||
let o = '';
|
||
const u = n % 10n;
|
||
n = (n - u) / 10n;
|
||
o = (u > 0 ? ones[u - 1n] : '') + o;
|
||
const t = n % 10n;
|
||
n = (n - t) / 10n;
|
||
o = (t > 0 ? tens[t - 1n] : '') + o;
|
||
const h = n % 10n;
|
||
n = (n - h) / 10n;
|
||
o = (h > 0 ? (h > 1 ? ones[h - 1n] : '') + "𐩆" : '') + o;
|
||
const th = n % 10n;
|
||
n = (n - th) / 10n;
|
||
o = (th > 0 ? (th > 1 ? ones[th - 1n] : '') + "𐩇" : '') + o;
|
||
|
||
return o;
|
||
}
|
||
},
|
||
|
||
phoenician: {
|
||
name: 'Phoenician',
|
||
fn: concatenative([
|
||
["𐤖","𐤚","𐤛","𐤛𐤖","𐤛𐤚","𐤛𐤛","𐤛𐤛𐤖","𐤛𐤛𐤚","𐤛𐤛𐤛",],
|
||
["𐤗","𐤘","𐤘𐤗","𐤘𐤘","𐤘𐤘𐤗","𐤘𐤘𐤘","𐤘𐤘𐤘𐤗","𐤘𐤘𐤘𐤘","𐤘𐤘𐤘𐤘𐤗"],
|
||
["𐤙","𐤚𐤙","𐤛𐤙","𐤛𐤖𐤙","𐤛𐤚𐤙","𐤛𐤛𐤙","𐤛𐤛𐤖𐤙","𐤛𐤛𐤚𐤙","𐤛𐤛𐤛𐤙"],
|
||
["𐤙","𐤘𐤙","𐤘𐤗𐤙","𐤘𐤘𐤙","𐤘𐤘𐤗𐤙","𐤘𐤘𐤘𐤙","𐤘𐤘𐤘𐤗𐤙","𐤘𐤘𐤘𐤘𐤙","𐤘𐤘𐤘𐤘𐤗𐤙"]
|
||
])
|
||
},
|
||
|
||
armenian: {
|
||
name: 'Armenian',
|
||
fn: concatenative([
|
||
['Ա','Բ','Գ','Դ','Ե','Զ','Է','Ը','Թ'],
|
||
['Ժ','Ի','Լ','Խ','Ծ','Կ','Հ','Ձ','Ղ'],
|
||
['Ճ', 'Մ', 'Յ', 'Ն', 'Շ', 'Ո', 'Չ', 'Պ', 'Ջ'],
|
||
['Ռ', 'Ս', 'Վ', 'Տ', 'Ր', 'Ց', 'Ւ', 'Փ', 'Ք'],
|
||
['Օ', 'Ֆ']
|
||
])
|
||
},
|
||
|
||
abjad: {
|
||
name: 'Arabic abjad',
|
||
fn: concatenative([
|
||
["ا","ب","جـ","د","هـ","و","ز","حـ","ط"],
|
||
["ى","ك","ل","مـ","ن","س","ع","ف","ص"],
|
||
["ق","ر","ش","ت","ث","خـ","ذ","ض","ظ"]
|
||
])
|
||
},
|
||
|
||
glagolitic: {
|
||
name: 'Glagolitic',
|
||
fn: concatenative([
|
||
span('Ⰰ',9),
|
||
span('Ⰹ',9),
|
||
span('Ⱃ',9),
|
||
span('Ⱍ',9),
|
||
])
|
||
},
|
||
|
||
cyrillic: {
|
||
name: 'Cyrillic',
|
||
fn: (() => {
|
||
const units = ["А","В","Г","Д","Є","Ѕ","З","И","Ѳ"];
|
||
const tens = ["І","К","Л","М","Н","Ѯ","Ѻ","П","Ч"];
|
||
const hundreds = ["Р","С","Т","У","Ф","Х","Ѱ","Ѡ","Ц"];
|
||
return concatenative([
|
||
units,
|
||
tens,
|
||
hundreds,
|
||
units.map(x => x+'҂'),
|
||
units.map(x => x+"\u200d\u20dd "),
|
||
units.map(x => x+'\u200d\u0488 '),
|
||
units.map(x => x+'\u200d\u0489 '),
|
||
units.map(x => x+'\u200d\ua670 '),
|
||
units.map(x => x+'\u200d\ua671 '),
|
||
units.map(x => x+'\u200d\ua672 '),
|
||
])
|
||
})()
|
||
},
|
||
|
||
tangut: {
|
||
name: 'Tangut',
|
||
fn: chinese_system(
|
||
'',
|
||
['',"𘈩","𗍫","𘕕","𗥃","𗏁","𗤁","𗒹","𘉋","𗢭"],
|
||
['𗰗', '𘊝', '𗡞'],
|
||
['', '𗕑', '𗦲']
|
||
)
|
||
},
|
||
|
||
hangul: {
|
||
name: 'Hangul',
|
||
fn: chinese_system(
|
||
'영',
|
||
['',"일","이","삼","사","오","육, 륙","칠","팔","구"],
|
||
['십','백','천'],
|
||
['','만','억','조','경','해','자','양','구','간','정','재','극','항하사','아승기','나유타','불가사의','무량대수']
|
||
)
|
||
},
|
||
|
||
// TODO: Cistercian (needs SVG?)
|
||
|
||
// TODO: Pentadic numerals (needs SVG?)
|
||
|
||
rumi: positional_unicode_span('Rumi', '𐹠'),
|
||
|
||
mayan: positional_unicode_span('Mayan', '𝋠', 20n, {orientation: 'vertical-lr'}),
|
||
|
||
nko: positional_unicode_span('N\'Ko', '߀'),
|
||
|
||
devanagari: positional_unicode_span('Devanagari', '०'),
|
||
|
||
bengali: positional_unicode_span('Bengali', '০'),
|
||
|
||
gurmukhi: positional_unicode_span('Gurmukhi','੦'),
|
||
|
||
gujarati: positional_unicode_span('Gujarati', '૦'),
|
||
|
||
odia: positional_unicode_span('Odia', '୦'),
|
||
|
||
tamil: positional_unicode_span('Tamil', '௦'),
|
||
|
||
telugu: positional_unicode_span('Telugu', '౦'),
|
||
|
||
kannada: positional_unicode_span('Kannada', '೦'),
|
||
|
||
malayalam: positional_unicode_span('Malayalam', '൦'),
|
||
|
||
thai: positional_unicode_span('Thai', '๐'),
|
||
|
||
lao: positional_unicode_span('Lao', '໐'),
|
||
|
||
tibetan: positional_unicode_span('Tibetan', '༠'),
|
||
|
||
burmese: positional_unicode_span('Burmese', '၀'),
|
||
|
||
khmer: positional_unicode_span('Khmer', '០'),
|
||
|
||
mongolian: positional_unicode_span('Mongolian', '᠐'),
|
||
|
||
limbu: positional_unicode_span('Limbu', '᥆'),
|
||
|
||
new_tai_lue: positional_unicode_span('New Tai Lue', '᧐'),
|
||
|
||
lek_hora: positional_unicode_span('Lek Hora','᪀'),
|
||
|
||
lek_nai_tham: positional_unicode_span('Lek Nai Tham', '᪐'),
|
||
|
||
balinese: positional_unicode_span('Balinese', '᭐'),
|
||
|
||
sundanese: positional_unicode_span('Sundanese', '᮰'),
|
||
|
||
lepcha: positional_unicode_span('Lepcha', '᱀'),
|
||
|
||
ol_chiki: positional_unicode_span('Ol Chiki', '᱐'),
|
||
|
||
vai: positional_unicode_span('Vai', '꘠'),
|
||
|
||
saurashtra: positional_unicode_span('Saurashtra', '꣐'),
|
||
|
||
kayah_li: positional_unicode_span('Kayah Li', '꤀'),
|
||
|
||
javanese: positional_unicode_span('Javanese', '꧐'),
|
||
|
||
cham: positional_unicode_span('Cham', '꩐'),
|
||
|
||
meitei: positional_unicode_span('meitei', '꯰'),
|
||
|
||
osmanya: positional_unicode_span('Osmanya', '𐒠'),
|
||
|
||
brahmi: positional_unicode_span('Brahmi', '𑁦'),
|
||
|
||
sorang_sompeng: positional_unicode_span('Sorang Sompeng', '𑃰'),
|
||
|
||
chakma: positional_unicode_span('Chakma', '𑄶'),
|
||
|
||
sharada: positional_unicode_span('Sharada', '𑇐'),
|
||
|
||
takri: positional_unicode_span('Takri', '𑛀'),
|
||
|
||
sinhala: positional_unicode_span('Sinhala', '෦'),
|
||
|
||
tai_laing: positional_unicode_span('Tai Laing', '꧰'),
|
||
|
||
khudabadi: positional_unicode_span('Khudabadi', '𑋰'),
|
||
|
||
tirhuta: positional_unicode_span('Tirhuta', '𑓐'),
|
||
|
||
modi: positional_unicode_span('Modi', '𑙐'),
|
||
|
||
warang_citi: positional_unicode_span('Warang Citi', '𑣠'),
|
||
|
||
mro: positional_unicode_span('Mro', '𖩠'),
|
||
|
||
pahawh_hmong: positional_unicode_span('Pahawh Hmong', '𖭐'),
|
||
|
||
ahom: positional_unicode_span('Tai Ahom', '𑜰'),
|
||
|
||
prachalit: positional_unicode_span('Prachalit', '𑑐'),
|
||
|
||
hanifi_rohingya: positional_unicode_span('Hanifi Rohingya', '𐴰'),
|
||
|
||
bhaiksuki: positional_unicode_span('Bhaiksuki', '𑱐'),
|
||
|
||
masaram_gondi: positional_unicode_span('Masaram Gondi', '𑵐'),
|
||
|
||
gunjala_gondi: positional_unicode_span('Gunjala Gondi', '𑶠'),
|
||
|
||
medefaidrin: positional_unicode_span('Medefaidrin', '𖺀', 20n),
|
||
|
||
nyiakeng_puachue_hmong: positional_unicode_span('Nyiakeng Puachue Hmong', '𞅀'),
|
||
|
||
wancho: positional_unicode_span('Wancho', '𞋰'),
|
||
|
||
adlam: positional_unicode_span('Adlam', '𞥐'),
|
||
|
||
kaktovik: positional_unicode_span('Kaktovik', '𝋀', 20n),
|
||
|
||
// garay: positional_unicode_span('Garay', ''), //(not in noto??)
|
||
|
||
binary: {
|
||
name: 'Binary',
|
||
fn: (n) => n.toString(2),
|
||
},
|
||
|
||
octal: {
|
||
name: 'Octal',
|
||
fn: (n) => n.toString(8),
|
||
},
|
||
|
||
hexadecimal: {
|
||
name: 'Hexadecimal',
|
||
fn: (n) => n.toString(16),
|
||
},
|
||
|
||
balanced_ternary: {
|
||
name: 'Balanced ternary',
|
||
fn: (n) => {
|
||
let o = '';
|
||
while(n) {
|
||
const r = n % 3n;
|
||
n = (n - r) / 3n;
|
||
if(r == 2) {
|
||
n += 1n;
|
||
}
|
||
o = ['0','+','-'][r] + o;
|
||
}
|
||
return o;
|
||
}
|
||
}
|
||
}
|
||
|
||
const dl = document.getElementById('systems');
|
||
|
||
Object.entries(systems).forEach(([id, entry]) => {
|
||
const {name, orientation} = entry;
|
||
const dt = document.createElement('dt');
|
||
dt.textContent = name;
|
||
dl.append(dt);
|
||
const dd = document.createElement('dd');
|
||
if(orientation) {
|
||
dd.style['writing-mode'] = orientation;
|
||
}
|
||
dl.append(dd);
|
||
entry.dd = dd;
|
||
})
|
||
|
||
function update() {
|
||
const n = BigInt(decimal_input.value || '0');
|
||
Object.values(systems).forEach(({name,fn,dd}) => {
|
||
console.log(name);
|
||
dd.textContent = fn(n);
|
||
});
|
||
}
|
||
|
||
const decimal_input = document.getElementById('decimal');
|
||
|
||
update();
|
||
|
||
decimal_input.addEventListener('input', update); |