2014-10-16 3 views
5

Oft ist es für Implementierungen von Programmiersprachen wünschenswert, Zahlen mit bitweisen Operatoren zu markieren. In C könnten Sie eine Doppelmarke mit einer Union kennzeichnen:Performanter Weg, um eine Nummer in JavaScript zu markieren, indem das weniger signifikante Bit verwendet wird?

typedef union Tag_ { double d; long long i; } Tag; 
double tag(double x){ Tag tmp; tmp.d = x; tmp.i |= 1; return tmp.d; }; 
double isTagged(double x){ Tag tmp; tmp.d = x; return tmp&1; }; 

Was ist eine Möglichkeit, dieses Verhalten auf JavaScript nachzuahmen? Die Verwendung von bitweisen Operatoren ist ausgeschlossen, da die Doubles in Uint32 konvertiert werden. Ich brauche eine mathematische Lösung.

+0

Warum möchten Sie das in JavaScript tun? Was ist dein tatsächlicher Anwendungsfall? – Bergi

+1

Kompilieren einer schemaartigen Sprache mit JavaScript. Da es keine getaggten Vereinigungen gibt, wäre die Verwendung der Bits auf dem Double, um sie zu simulieren, sicherlich viel schneller als das Erstellen von Objekten, da es beispielsweise ermöglichen würde, typisierte Arrays für meine Stapel zu verwenden. – MaiaVictor

+2

Ich verstehe. Ich wollte bereits vorschlagen, ein typisiertes Array zu verwenden, da Sie einfach ein 'Uint32Array' und ein' Float64Array' auf dem * selben * Puffer verwenden können; Ich dachte jedoch, dass das Erstellen dieser drei Objekte kein Gewinn gegenüber dem "nicht-unionierten" Objektliteral wäre. Aber wenn du sie trotzdem verwendest ... – Bergi

Antwort

1

Dies hat keine Antwort erhalten, vielleicht haben Sie eine gefunden? Wenn nicht:

Lassen Sie mich mit der Frage in Ihren Kommentaren beginnen, wie es klingt wie die Lösung dieser Frage am Ende löst die ursprüngliche Frage.

Wie kann ich getrennte Ansichten desselben Arrays erstellen?

Dies ist im Wesentlichen Bergi's proposal aus den Kommentaren, leicht modifiziert. Es beantwortet die How.

Wenn Sie eine ArrayBuffer erstellen, können Sie auf das zugrunde liegende Array von Bytes aus mehreren typisierten Arrays zugreifen, indem Sie diesen Array-Puffer als Anfangsparameter übergeben. Ich habe JavaScripture -- ArrayBuffer gefunden, um in der Vergangenheit mit TypedArrays ziemlich hilfreich zu sein. Das Folgende reserviert also 8 Bytes im Speicher und greift darauf sowohl als 64-Bit-Float als auch als 8-Byte-Ints zu.

var myBuff = new ArrayBuffer(8); 
var myU8Arr = new Uint8Array(myBuff); 
var myFloat64Arr = new Float64Array(myBuff); 

also, wenn Sie das erste Byte in dem Puffer auf 1 sagen gesetzt, und Zugriff dann diesen Wert von dem Schwimmer Sie ein narly schweben bekommen: So

myFloat64Arr[0] = 10000; 
console.log(myFloat64Arr[0])//prints 0; 
myU8Arr[7] |= 128;//sets sign bit of IEEE 754 Double-precision float. 
//setting the sign because it's more straightforward than if another 
//bit was to be set. 
console.log(myFloat64Arr[0]);//prints -10000 ... all dependent on system endianess 

, jetzt, dass die Frage von die Kommentare wurden beantwortet:

Wie kann ich das niedrigstwertige Bit verwenden, um meine Nummern zu markieren?

Direkte Adressierung der Frage; Ich sehe kein Problem mit den typisierten Arrays. Wir können bitweise auf die zugrunde liegenden Bytes im zugrunde liegenden Array-Puffer zugreifen, ohne uns Gedanken darüber machen zu müssen, ob das Byte in einen 64-Bit-Float umgewandelt wird und die Dinge durcheinander bringt.

Wenn Sie mit Ihrem "Stapel" an Schwimmern kleben, erhalten Sie die zusätzliche Leistung. Einfach erstellen Sie die ArrayBuffer und dann sowohl die Uint8Array und Float64Array anstelle eines Arrays von Zahlen (oder ein Array von Tag s). Ansonsten könntest du eine Tag Funktion mit ArrayBuffer, Uint8Array und Float64Array Attributen in ihrem Gültigkeitsbereich machen und dann neue Instanzen für jede Zahl erstellen ... aber das spart dir nicht viel von irgendetwas im Javascript-Bereich. Könnte auch Polyfill in einem tag Attribut/Funktion auf Variablen und der Zahl-Prototyp, wenn Sie den Weg des Erstellens Tag-like Strukturen gehen. Es wird nicht die Speicherleistung geben, aber zumindest das Tag mit jeder Nummer gekoppelt halten.

Wegen der Endianess und da es kein 64-Bit Integer-Array gibt, müssen Sie den Index des LSB etwas anders handhaben. Prüfe die Endianess und setze eine globale Variable, oder was auch immer du am besten siehst.auf einem kleinen Endian-System:

var globalMyBuff = new ArrayBuffer(n);//n is your number of floats * 8 (8 bytes per float) 
var globalMyU8Arr = new Uint8Array(globalMyBuff); 
var globalMyFloat64Arr = new Float64Array(globalMyBuff); 

//Load your floats into globalMyFloat64Arr 

//tag a float at index when desired 
function tag(index){ 
    //"index << 3 " is essentially the same as "index * 8", but faster 
    //since it will get compiled into a shift op 
    myU8Arr[index << 3] |= 1;//sets the LSB 
} 
//check tag at index when desired 
function isTagged(index){ 
    //"index << 3 " is essentially the same as "index * 8", but faster 
    //since it will get compiled into a shift op 
    return (myU8Arr[index << 3] & 1) == 1;//checks LSB 
} 
+1

Leider war die Verwendung eines Arrays viel zu langsam auf meinen Benchmarks. Es ist jedoch wahrscheinlich die flexibelste Lösung. Für meinen speziellen Fall hatte ich bessere Ergebnisse mit IEEE 754-Arithmetik, um die Bits auf Gleitkommazahlen zu manipulieren, da JS das schnell macht. Vielen Dank! – MaiaVictor

+0

Ich dachte, du hättest das schon gelöst, aber du hast die Frage gesehen und gemerkt, dass ich eine Antwort wusste :) Freut mich zu hören, dass du eine Lösung hast und dass du mit dem passt, was für deinen Fall am besten ist! –

+1

Ja, ich weiß! Vielen Dank. Ich könnte auch meine eigene Lösung veröffentlichen, aber ich habe gerade einen engen Zeitplan, so dass ich warten muss ... – MaiaVictor

Verwandte Themen