Pensons à la situation suivante. P>
La routine Go crée un tableau d'octets où Packs A UINT64 EM> Number dans le code JavaScript, je reçois ces octets comme Alors, quel est le processus de décodage de ces octets directement à la chaîne numérique PS strong> Je sais qu'il y a beaucoup 5577006791947779410 Code> Dans 8 octets Big Endian
[77, 101, 130, 33, 7, 252 , 253, 82] code>. P>
uint8array code>. Nous savons que JavaScript ne prend pas en charge actuellement uint64 em> comme type numérique sûr et ne peut pas effectuer les opérations binaire sur des entiers supérieurs à 32 bits, donc des choses comme
buf [0] << / code> ne travaillera jamais. p>
"5577006791947779410" code>? P>
4 Réponses :
EDIT: strong> pour la conversion (U) INT64, je recommanderais désormais la solution de @ ls_dev. J'utiliserais ma solution que lorsque vous avez une quantité inconnue ou plus importante d'octets. J'ai commencé avec https://stackoverflow.com/ A / 21668344/3872370 et modifié et modifié: p> p> function Int64ToString(bytes, isSigned) {
const isNegative = isSigned && bytes.length > 0 && bytes[0] >= 0x80;
const digits = [];
bytes.forEach((byte, j) => {
if(isNegative)
byte = 0x100 - (j == bytes.length - 1 ? 0 : 1) - byte;
for(let i = 0; byte > 0 || i < digits.length; i++) {
byte += (digits[i] || 0) * 0x100;
digits[i] = byte % 10;
byte = (byte - digits[i]) / 10;
}
});
return (isNegative ? '-' : '') + digits.reverse().join('');
}
const tests = [
{
inp: [77, 101, 130, 33, 7, 252, 253, 82],
signed: false,
expectation: '5577006791947779410'
},
{
inp: [255, 255, 255, 255, 255, 255, 255, 255],
signed: true,
expectation: '-1'
},
];
tests.forEach(test => {
const result = Int64ToString(test.inp, test.signed);
console.log(`${result} ${result !== test.expectation ? '!' : ''}=== ${test.expectation}`);
});
Merci pour la réponse! Cela semble bien fonctionner pour uint64 code>. Quelles modifications dois-je avoir besoin de faire pour que cela fonctionne avec
int64 code> aussi? J'ai créé une aire de jeux ici: jsfiddle.net/wcqlj1qg .
J'ai mis à jour ma réponse et l'a téléchargé sur CodePen.io/stephtr/pen/brbvxr Les modifications Les obligations nécessaires sont (évidemment) en ajoutant le signe moins, nier les bits et le soustraction 1.
Pourrait le rendre légèrement plus compact en modifiant octet> 0 code> à
octet code> car
octet code> est toujours positif. Aussi
j == octets.length - 1? 0: 1 code> peut être écrit simplement
j! = Bytes.length - 1 code> puisque le booléen sera contraint à un numéro :)
J'ai réfléchi à cela lors de la rédaction du code, mais à mon avis qui diminue la lisibilité.
Voici ma solution. La stratégie générale est la suivante:
uint8array code> (du plus au moins significatif), multipliez le total de l'exécution de 256 et ajoutez-lui la valeur du nouvel octet li>
- Pour multiplier un nombre par 256, double-le 8 fois (depuis
2 ** 8 == 256 code>) li>
- Pour ajouter deux chiffres, utilisez l'algorithme de l'école primaire:
- Commencez avec le chiffre moins significatif li>
- Ajouter des chiffres correspondants des deux numéros li>
- Le chiffre résultant est la somme MOD 10; Le transport est 1 si la somme est de 10 ou plus, sinon 0 li>
- Continuez à ajouter des chiffres correspondants avec le transport jusqu'à ce que nous ajoutons les chiffres les plus significatifs et le transport est 0 li>
ul> li>
ul>
Quelques notes sur le sténographie: p>
-
n1 [i] || 0 code> obtient le i code> th chiffre de N1 code>. Si cela est passé la fin de i code>, nous le traitons comme un 0 (numéros imaginaires représentés avec des 0s infinis devant eux). Même avec n2 code>. Li>
-
ajouté> 9 code> produit un booléen, qui est automatiquement converti en un numéro (1 si ajouté> = 10 code>, 0 sinon) li>
-
i vérifie s'il y a plus de chiffres dans l'un des ajouts ou le port est toujours non nul li>
-
string (b) .split (''). mappe (numéro) .Reverse () code> convertit, par exemple. 100 code> à '100' code>, puis ['1', '0', '0', '0'] code>, puis [1, 0 , 0] code>, puis [0, 0, 1] code> de sorte qu'il est représenté dans le base-10 li>
-
résultat.Reverse (). Joindre ('') Code> Convertit, par ex. [0, 0, 1] code> à [1, 0, 0] code>, puis '100' code> li> li>
ul> code: p> xxx pré> p>
Merci beaucoup pour votre réponse. Votre code et votre explication sont simplement géniaux. Maintenant, je me demande quelle solution est meilleure: votre ou Stephan's . Sa solution est plus courte et ne contient que 2 boucles, votre stratégie est plus détaillée et claire. Nous avons probablement besoin de la vérification des perfs ici.
Oui, je suis sûr que c'est probablement plus rapide, mais j'ai trouvé cela plus facile à conceptualiser.
Ceci fait la version p> uint64 code> - Je ne peux pas imaginer qu'un interchange est que em> difficile:
<!DOCTYPE html>
<html>
<body>
<span id='out1'></span>
<br>
<span id='out2'></span>
<br>
<span id='out3'></span>
</body>
<script>
fnl='';
be=[77, 101, 130, 33, 7, 252, 253, 82];
function paddedBinary(n) {
pad='';
sv=128;
while (sv>n) {pad+='0';sv/=2;}
return pad+n.toString(2);
}
for (let i=0;i<8;i++)
fnl+=paddedBinary(be[i]);
out1.textContent=fnl;
dec=new Array(64);
for (let i=0;i<64;i++) dec[i]=new Array(21).fill(0);
function make2s() {
dec[0][0]=1;
for (let i=1;i<64;i++) {
for (let j=0;j<21;j++)
dec[i][j]=2*dec[i-1][j];
for (let j=0;j<21;j++)
if (dec[i][j]>9) {
dec[i][j]-=10;
dec[i][j+1]++;
}
}
}
function int64add(v1,v2) {
var res=new Array(21).fill(0);
for (let i=0;i<21;i++)
res[i]=v1[i]+v2[i];
for (let i=0;i<21;i++)
if (res[i]>9) {
res[i]-=10;
res[i+1]++;
}
return res;
}
make2s();
for (let i=0;i<64;i++)
out2.textContent+=dec[i]+' :: ';
cv=new Array(21).fill(0);
for (let i=0;i<fnl.length;i++)
if (fnl[i]=='1') cv=int64add(cv,dec[63-i]);
out3.textContent=cv;
</script>
</html>
Merci pour la réponse!
Une autre approche: diviser le problème dans deux UINT32 pour maintenir les calculs gérable.
Considérez UINT32 inférieur et supérieur ( P> l code> et
h code>). Le nombre total pourrait être écrit comme
H * 0x10000000000 + L code>. Considérant décimal, on pourrait également considérer les 9 chiffres inférieurs et les chiffres plus élevés (
ld code> et
hd code>):
ld = (h * 0x100000000 + l)% 1000000000 Code> et
HD = (h * 0x10000000000 + L) / 1000000000 code>. Avec certains propriétés de l'arithmétique et d'algèbre des opérateurs, on peut briser ces opérations dans des opérations de 64 bits sûres sûres et composer une chaîne à la fin. P>
function int64_to_str(a, signed) {
const negative = signed && a[0] >= 128;
const H = 0x100000000, D = 1000000000;
let h = a[3] + a[2] * 0x100 + a[1] * 0x10000 + a[0]*0x1000000;
let l = a[7] + a[6] * 0x100 + a[5] * 0x10000 + a[4]*0x1000000;
if(negative) {
h = H - 1 - h;
l = H - l;
}
const hd = Math.floor(h * H / D + l / D);
const ld = (((h % D) * (H % D)) % D + l) % D;
const ldStr = ld + '';
return (negative ? '-' : '') +
(hd != 0 ? hd + '0'.repeat(9 - ldStr.length) : '') + ldStr;
}
let result = int64_to_str([77, 101, 130, 33, 7, 252, 253, 82], false);
let expectation = '5577006791947779410';
console.log(result + ' ' + (result === expectation ? '===' : '!==') + ' ' + expectation);
result = int64_to_str([255, 255, 255, 255, 255, 255, 255, 255], true);
expectation = '-1';
console.log(result + ' ' + (result === expectation ? '===' : '!==') + ' ' + expectation);
Même si ce serait la meilleure approche pour traiter avec la taille fixe et que cela ne fonctionnera pas correctement dans certains cas. Je pense que la partie math.trunch (ld / d) code> doit être supprimée puisque le premier Summand contient déjà cette partie. Avec cela corrigé, je ne suis toujours pas sûr que cela fonctionne correctement.
H * H code> peut entraîner des chiffres ci-dessus
numéro.max_safe_integer code>. En divisant cela avec
d code> et tronquage, la perte de précision devrait disparaître. Cependant, je suis plus inquiet pour
(h% d) * (h% d) code>, puisque
d * (h% d) code> est également trop grand, cette fois-ci avec le la précision complète étant nécessaire.
@Stephan (h% d) * (h% d) code>, c'est un bon point! Je pourrais utiliser 3 uint22, mais pas aujourd'hui ...
J'ai expérimenté un peu un peu et il semble que l'erreur introduite dans la multiplication ait heureusement compensée par l'erreur introduite lors du calcul du module (car d code> et
h code> sont divisibles par 0x800) . Il n'est pas nécessaire de la diviser en trois groupes. Si vous ne voulez pas compter sur ce comportement, vous pouvez utiliser
((((h% d) * ((h% d) / 0x800))% d) * 0x800)% d code> au lieu de
(h% d) * (h% d)% d code> (car
d * (h% d) / 0x800 code> est plus petit que
numéro.max_safe_integer code >).
Pour être plus spécifique, les 11 derniers bits (donc 0x800) de d code> et donc
h% d code> sont déjà nuls, donc il n'y a donc aucune erreur introduite en les définissant implicitement. zéro en raison de la "perte de précision". Juste une autre note: lorsque
HD code> est zéro que les zéros de premier plan ne doivent pas être ajoutés.
J'ai mis à jour votre code pour inclure le support INT signé et une solution pour HD code>: CODEPEN.IO/STEPHTR/PEN/EVXQOP?Editors=0010
@Stephan beau travail. Si vous le souhaitez, vous êtes invité à la poster comme une réponse. Vous avez passé beaucoup plus d'efforts que moi :-)
J'ai mis à jour votre réponse, mais la modification a été déclinée d'une manière ou d'une autre. N'hésitez pas à le copier;)
Merci pour la réponse! J'aimerais pouvoir vous donner tous plus de upvotes ;) code>