2010-12-10 28 views
19

Có cách nào tôi có thể đọc byte của giá trị float trong JS không? Những gì tôi cần là viết một giá trị FLOAT hoặc DOUBLE thô thành một số định dạng nhị phân mà tôi cần phải thực hiện, vậy có cách nào để có được một biểu diễn IEEE 754 từng byte không? Và cùng một câu hỏi để viết tất nhiên.Đọc/ghi byte trôi nổi trong JS

Trả lời

4

Cần this snippet trợ giúp?

@Kevin Gadd:

var parser = new BinaryParser 
    ,forty = parser.encodeFloat(40.0,2,8) 
    ,twenty = parser.encodeFloat(20.0,2,8); 
console.log(parser.decodeFloat(forty,2,8).toFixed(1)); //=> 40.0 
console.log(parser.decodeFloat(twenty,2,8).toFixed(1)); //=> 20.0 
+1

+1 khá đẹp – Zevan

+0

Tuyệt vời! Điều này có vẻ chính xác những gì tôi cần. –

+4

Thuật toán được sử dụng trong đoạn mã đó bị hỏng hoàn toàn. Nó không thành công trên các giá trị cụ thể khi được sử dụng để đọc nổi hoặc tăng gấp đôi. Ví dụ: , nó đọc 40,0 là 32,0 và 20,0 là 16,0. –

0

Tôi hy vọng bạn có thể tìm ra (blech), nhưng tôi cho rằng bạn đang hỏi liệu có điều gì đó được tích hợp sẵn hay không. Không xa như tôi từng nghe; xem phần 8.5 và 15.7 của the spec.

3

đoạn Koolinc là tốt nếu bạn cần một giải pháp mạnh mẽ, nhưng nếu bạn cần nó để sử dụng hạn chế bạn là tốt hơn viết mã của riêng bạn. Tôi đã viết hàm sau để chuyển đổi một chuỗi đại diện hex byte vào một float:

function decodeFloat(data) { 
    var binary = parseInt(data, 16).toString(2); 
    if (binary.length < 32) 
     binary = ('00000000000000000000000000000000'+binary).substr(binary.length); 
    var sign = (binary.charAt(0) == '1')?-1:1; 
    var exponent = parseInt(binary.substr(1, 8), 2) - 127; 
    var significandBase = binary.substr(9); 
    var significandBin = '1'+significandBase; 
    var i = 0; 
    var val = 1; 
    var significand = 0; 

    if (exponent == -127) { 
     if (significandBase.indexOf('1') == -1) 
      return 0; 
     else { 
      exponent = -126; 
      significandBin = '0'+significandBase; 
     } 
    } 

    while (i < significandBin.length) { 
     significand += val * parseInt(significandBin.charAt(i)); 
     val = val/2; 
     i++; 
    } 

    return sign * significand * Math.pow(2, exponent); 
} 

Có giải thích chi tiết các thuật toán sử dụng để chuyển đổi theo cả hai hướng cho tất cả các định dạng của các điểm nổi trên wikipedia, và nó rất dễ dàng để sử dụng chúng để viết mã của riêng bạn. Việc chuyển đổi từ một số sang byte sẽ khó khăn hơn vì bạn cần chuẩn hóa số đầu tiên.

+2

Tôi đã mở rộng giải pháp này để xử lý phao 64 bit và mã hóa nhỏ gọn.Nó cũng có một mảng các byte thay vì một chuỗi base-16 (để các float 64 bit hoạt động tốt mà không làm tròn các vấn đề). https://gist.github.com/2192799 –

35

Bạn có thể làm điều đó với typed arrays:

var buffer = new ArrayBuffer(4); 
var intView = new Int32Array(buffer); 
var floatView = new Float32Array(buffer); 

floatView[0] = Math.PI 
console.log(intView[0].toString(2)); //bits of the 32 bit float 

Hoặc một cách khác:

var view = new DataView(new ArrayBuffer(4)); 
view.setFloat32(0, Math.PI); 
console.log(view.getInt32(0).toString(2)); //bits of the 32 bit float 

Không chắc những gì hỗ trợ trình duyệt giống như dù

+3

Cool, TIL 'Double' được gọi là' Float64' trong Javascript. Tôi đang tìm kiếm 'DoubleArray' - không có kết quả - nhưng' Float64Array' tồn tại và có vẻ hữu ích với tôi –

+1

Lưu ý rằng đây là * không * được hỗ trợ trong IE9! – Qix

+1

Dường như bạn có thể sử dụng 'Uint8Array' (ít nhất là trong Chrome) thay vì' Int32Array' để dễ dàng nhận được tại các byte riêng lẻ –

6

tôi đã tạo ra một sự mở rộng của Milos' giải pháp mà nên được một chút nhanh hơn, giả sử TypedArrays không phải là một lựa chọn tất nhiên (trong trường hợp của tôi tôi đang làm việc với một môi trường mà họ không có sẵn):

function Bytes2Float32(bytes) { 
    var sign = (bytes & 0x80000000) ? -1 : 1; 
    var exponent = ((bytes >> 23) & 0xFF) - 127; 
    var significand = (bytes & ~(-1 << 23)); 

    if (exponent == 128) 
     return sign * ((significand) ? Number.NaN : Number.POSITIVE_INFINITY); 

    if (exponent == -127) { 
     if (significand == 0) return sign * 0.0; 
     exponent = -126; 
     significand /= (1 << 22); 
    } else significand = (significand | (1 << 23))/(1 << 23); 

    return sign * significand * Math.pow(2, exponent); 
} 

Cho số nguyên chứa 4 byte chứa một float chính xác đơn IEEE-754 32-bit, điều này sẽ tạo ra giá trị số chính xác (xấp xỉ) mà không sử dụng bất kỳ vòng lặp nào.

+1

'if (significand == 0) trả về dấu * 0,0;' - chắc chắn bất cứ điều gì lần zero là ... số không? '-1 * 0.0' có tạo ra số không âm? – Nick

+0

@Nick: Vâng, nó có – Eric

+0

@Haravikk, Còn về việc đại diện bit của một số thì sao? – Pacerier

1

Tôi gặp vấn đề tương tự, tôi muốn chuyển đổi bất kỳ số javascript nào thành Bộ đệm rồi phân tích cú pháp ngược lại mà không cần xâu chuỗi.

function numberToBuffer(num) { 
    const buf = new Buffer(8) 
    buf.writeDoubleLE(num, 0) 
    return buf 
} 

Sử dụng ví dụ:

// convert a number to buffer 
const buf = numberToBuffer(3.14) 
// and then from a Buffer 
buf.readDoubleLE(0) === 3.14 

này hoạt động trên hiện tại Node LTS (4.3.1) trở lên. không thử nghiệm ở các phiên bản thấp hơn.

+0

Tôi có thể xác nhận rằng điều này cũng hoạt động trên Node.js 0.10.40. Với phiên bản cũ của tôi của Node-RED (0.11.1) tôi rõ ràng là không có quyền truy cập vào Float32Array vì vậy giải pháp của bạn là người duy nhất cho tôi! Tôi sử dụng 'Bộ đệm mới (mảng)' để tạo Bộ đệm từ mảng phao nhị phân 4 byte và buffer.readFloatBE (0) để truy xuất phao. – winne2

Các vấn đề liên quan