沿著如何讓這個 PRNG 生成范圍內的數字?,我到此為止(parts是一個包含 32 個 2 字符“符號”的陣列):
const parts = `mi
ma
mo
ne
nu
di
da
do
be
bu
ti
te
ta
to
tu
ki
ke
ka
ko
ku
si
sa
so
ze
zu
fi
fa
fo
ve
vu
xe
xu`.trim().split(/\n /)
const fetch = (x, o) => {
if (x >= o) {
return x
} else {
const v = (x * x) % o
return (x <= (o / 2n)) ? v : o - v
}
}
const fetchLarge = (x) => fetch(x, 41223334444555556666667777777888888889999999997n)
// the last number can be anything.
const buildLarge = (x, o) => fetchLarge((fetchLarge(x) o) % BigInt(Math.pow(32, 31)) ^ 2030507011013017019023n)
const createArray = (n, mod = 32n) => {
if (!n) return [0];
let arr = [];
while (n) {
arr.push(Number(n % mod));
n /= mod;
}
return arr;
}
const write = (i) => {
const x = buildLarge(i , 272261127249452727280272961627319532734291n)
return createArray(x).map(x => parts[x]).join('')
}
let i = 1n
while (i < 10000) {
console.log(write(i))
}
我正在生成以下方面的結果:
kitekutefaxunetotuzezumatotamabukidimasoxumoxudofasositinu,6038940986212279582529645303138677298679151
sokiketufikefotekakidotetotesamizununetefokixefitetisovene,5431347628569519336817719657935192515363318
xudamituzesimixuxemixudakedatetutununekobuzexesozuxedinenu,5713969289948157459645315228321450728816863
dazenenemovudadikukatatakibekaxexemovubedivusidatafisasine,5082175912370834928186684152014555456835302
xufotidosokabunudomimibefisimakusimokedamomazexekofomokane,4925740069222414438181195472381794794580863
sodozekadakuzemaxetexukuzumisikitazufitizexekatetotuxusone,5182433137814021540565892366585827483507958
kikokasatudatidatufikizesadimatakakatudisibumofotuzutaze,1019165422643074024784461594259815846823503
dakikinetofonexesimavufafisaxefosafisikofotasanekovetevu,1279315636939618596561544978621478602915302
kinunebebuzukokemidatekobusofokikozukobedodakesisikunuki,659622269329577207976266617866288582888591
sozesifamoxebusitotesisasizekudasomitatavudidizukadimate,480714979099063166920265752208932468511478
xumakikofakumixefotisikunumovudafasofikimozenudafosidaka,749508057657951412178315361964670398839871
dazedokutituzufakebutifokekusobuzutemanesadafadatetitamo,103886097260879003150138325027254855900902
xukemizukozefaxetudizukedimotevubesitekitavukakevutisibe,376136321524704717800574424940622855799327
dozexedivenudifabuvedavebukeketozukumasimakuvetuketomafaxe,42948292938975784099596927092482269526555367
mimasatukidisodifikekutovumazefikefonemofimotesonusazexuxe,43196343143305047528500657761292227037320224
zedafimasobukudizedozefoketuzekisadotufikudadokisakedofoxe,43000150124549846140482724444846720574088407
kisafimosotuvuvuzuzukodibevutemidazusisamokososikomofavuma,2692423943832809210699522830552769656612527
soxutokonebusidaketesomoxemibesonubudibekunumatifokokanemo,2942202721014541374299446744441542204274678
xusikematetemititafafakuxusinekefoketonebetokudonesomosama,2312137916289687577537008913213461971911327
我如何才能使所有字串的長度為 31 個“符號”(因為在此示例中符號為 2 個字符,因此總共 62 個字符),如下所示:
xusikematetemititafafakuxusinekexusikematetemititafafakuxusine
那就是:演算法中上面的 3 個 bigint 數字應該是什么?另外,它們應該是什么,所以分布看起來是隨機的?我注意到,與較小的數字相比,使用靠近邊界的大數字會產生更好的明顯隨機結果。此外,您不能只在 bigint 前面x加上 0,這會導致mamamamamama.... 最后,一個序列中最多可以有 2 對相同的字母,我假設您只能通過跳過不符合該約束的結果來真正解決(除非有一些數學魔法可以以某種方式判斷更多這 32 個“符號”中的兩個彼此相鄰)。
關于最后一部分,這些是有效的結果:
mamavumamavumama...
nanavumamavuvuma...
這些無效:
mamamavumamavuma...
mavuvuvumamavuma...
因為連續有 3 對是相同的。
總結一下:
- How to make it so all strings are 62 characters in length, without padding with zeroes? That means it must fit within some range of BigInts I'm not too sure about.
- So that the distribution appears enormously random (i.e. so we don't get just the tail tip of the sequence changing slowly, but instead the entire number seems to completely change, as the examples show).
- So that no more than two pairs are similar in a sequence? This part can just be solved by skipping results we find in the pseudo-randomized sequence, unless there is some magic to accomplish it that I'm not possibly fathoming :) For example, maybe there is some magic to do with multiples of similar 5-bit chunks or something, I don't know. But don't need to get fancy, skipping the results that match a regex is fine too.
uj5u.com熱心網友回復:
在這里,我們使用 Base 32(硬編碼,但可能是parts.length)作為 2 ( maxRepeat) 個最低有效數字,使用 Base 31(硬編??碼,但可能是parts.length-1)作為其余數字。這給出了長度值的最大范圍。
從0nto 到 的所有值getMax()都可以編碼為 31 ( minLength) 個符號。
用于防止重復長于魔術maxRepeat是檢查i個數位抵靠i - maxRepeat位,使得調整到i如果個數位>=。雖然這會產生有效的編碼(遵循規則的編碼),但并非所有任意符號序列都是有效的,即使它們遵循規則。例如,序列mimami永遠不會生成,也無法解碼。
const split = new RegExp(`.{2}`, 'g');
const parts = 'mimamonenudidadobebutitetatotukikekakokusisasozezufifafovevuxexu'.match(split);
const partsMap = Object.fromEntries(parts.map((v,i) => ([v,BigInt(i)])));
const encode = (value, maxRepeat = 2, minLength = 31) => {
value = BigInt(value);
const digits = [];
// convert the value to digits
// the first least significant `maxRepeat` digits use base 32, the rest use base 31
while(value > 0) {
const radix = digits.length < maxRepeat ? 32n : 31n;
digits.push(value % radix);
value /= radix;
}
// add 0 padding
while(digits.length < minLength) {
digits.push(0n);
}
// adjust digits to prevent sequences longer than `maxRepeat`
const symbols = []
digits.forEach((v,i) => {
symbols.push((i < maxRepeat || v < symbols[i-maxRepeat]) ? v : v 1n);
});
// map to symbols and return string
const str = symbols.map(v => parts[v]).join('');
return str;
};
const decode = (str, maxRepeat = 2) => {
// split string into array of symbols
const symbols = str.match(split);
// convert symbols to digits
const digits = symbols.map(v => partsMap[v]).map((v,i,a) => {
if(i < maxRepeat || v < a[i-maxRepeat]) return v;
return v-1n;
});
// compute the threshold where we transition from base 31 to base 32
const threshold = digits.length - maxRepeat;
// convert digits to BigInt
const results = digits.reverse().reduce(
(s,v,i) => (s * (i >= threshold ? 32n : 31n) v)
, 0n);
return results;
};
// compute the maximum value that can be encoded using `minLength` number of symbols
const getMax = (maxRepeat = 2, minLength = 31) => 32n ** BigInt(maxRepeat) * 31n ** BigInt(minLength - maxRepeat) - 1n;
// Consoles will print BigInt but Stackoverflow's interpreter
// doesn't understand them yet so we use `.toString()`.
console.log('limit:', getMax().toString());
console.log(encode(getMax()));
const n1 = 6038940986212279582529645303138677298679151n;
console.log(encode(n1)); // 'kitefitifomazekosaxubezutatudofotudimidanemadanumasisivebumimi'
const n2 = 0n;
console.log(encode(n2)); // 'mimimamamimimamamimimamamimimamamimimamamimimamamimimamamimima'
const s1 = 'kitefitifomazekosaxubezutatudofotudimidanemadanumasisivebumimi';
console.log(decode(s1).toString()); // 6038940986212279582529645303138677298679151
const s2 = 'mimimamamimimamamimimamamimimamamimimamamimimamamimimamamimima';
console.log(decode(s2).toString()); // 0
console.log(decode(encode(0n)) == 0n);
console.log(decode(encode(6038940986212279582529645303138677298679151n)) == 6038940986212279582529645303138677298679151n);
.as-console-wrapper { max-height: 100% !important; top: 0; }
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/404669.html
標籤:
