精华内容
下载资源
问答
  • JavaScript-二进制二进制数组

    万次阅读 2016-07-03 18:09:40
    在ES5中引入了Blob用于处理二进制。在ES6中引入了ArrayBuffer、TypedArray、DataView用于处理二进制数组。常规的前端操作用,用到二进制的地方不多。但是,当我想处理文件的传输时候,使用二进制进行传输可以更快。...

    在ES5中引入了Blob用于处理二进制。在ES6中引入了ArrayBuffer、TypedArray、DataView用于处理二进制数组。常规的前端操作用,用到二进制的地方不多。但是,当我想处理文件的传输时候,使用二进制进行传输可以更快。在进行异步数据传输(AJAX)时,很可能出现这种场景。

    Blob

    Blob(Binary Large Object)对象代表了一段二进制数据,提供了一系列操作接口。其他操作二进制数据的API(比如File对象),都是建立在Blob对象基础上的,继承了它的属性和方法。

    生成Blob对象有两种方法:一种是使用Blob构造函数,另一种是对现有的Blob对象使用slice方法切出一部分。

    (1)Blob构造函数,接受两个参数。第一个参数是一个包含实际数据的数组,第二个参数是数据的类型,这两个参数都不是必需的。

    var htmlParts = ["<a id=\"a\"><b id=\"b\">hey!<\/b><\/a>"];
    var myBlob = new Blob(htmlParts, { "type" : "text\/xml" });

    下面是一个利用Blob对象,生成可下载文件的例子。

    var blob = new Blob(["Hello Lee"]);
    
    var a = document.createElement("a");
    a.href = window.URL.createObjectURL(blob);
    a.download = "hello-lee.txt";
    a.textContent = "Download Hello World!";
    
    body.appendChild(a);

    上面的代码生成了一个超级链接,点击后提示下载文本文件hello-lee.txt,文件内容为“Hello Lee”。

    (2)Blob对象的slice方法,将二进制数据按照字节分块,返回一个新的Blob对象。

    var newBlob = oldBlob.slice(startingByte, endindByte);

    下面是一个使用XMLHttpRequest对象,将大文件分割上传的例子。

    function upload(blobOrFile) {
      var xhr = new XMLHttpRequest();
      xhr.open('POST', '/server', true);
      xhr.onload = function(e) { ... };
      xhr.send(blobOrFile);
    }
    
    document.querySelector('input[type="file"]').addEventListener('change', function(e) {
      var blob = this.files[0];
    
      const BYTES_PER_CHUNK = 1024 * 1024; // 1MB chunk sizes.
      const SIZE = blob.size;
    
      var start = 0;
      var end = BYTES_PER_CHUNK;
    
      while(start < SIZE) {
        upload(blob.slice(start, end));
    
        start = end;
        end = start + BYTES_PER_CHUNK;
      }
    }, false);
    
    })();

    (3)Blob对象有两个只读属性:

    • size:二进制数据的大小,单位为字节。
    • type:二进制数据的MIME类型,全部为小写,如果类型未知,则该值为空字符串。
      在Ajax操作中,如果xhr.responseType设为blob,接收的就是二进制数据。

    二进制数组

    (1)ArrayBuffer对象:代表内存之中的一段二进制数据,可以通过“视图”进行操作。“视图”部署了数组接口,这意味着,可以用数组的方法操作内存。

    (2) TypedArray对象:用来生成内存的视图,通过9个构造函数,可以生成9种数据格式的视图,比如Uint8Array(无符号8位整数)数组视图, Int16Array(16位整数)数组视图, Float32Array(32位浮点数)数组视图等等。

    (3)DataView对象:用来生成内存的视图,可以自定义格式和字节序,比如第一个字节是Uint8(无符号8位整数)、第二个字节是Int16(16位整数)、第三个字节是Float32(32位浮点数)等等。

    简单说,ArrayBuffer对象代表原始的二进制数据,TypedArray对象代表确定类型的二进制数据,DataView对象代表不确定类型的二进制数据。它们支持的数据类型一共有9种(DataView对象支持除Uint8C以外的其他8种)。

    ArrayBuffe对象

    概述

    ArrayBuffer对象代表储存二进制数据的一段内存,它不能直接读写,只能通过视图(TypedArray视图和DataView视图)来读写,视图的作用是以指定格式解读二进制数据。

    ArrayBuffer也是一个构造函数,可以分配一段可以存放数据的连续内存区域。

    var buf = new ArrayBuffer(32);

    上面代码生成了一段32字节的内存区域,每个字节的值默认都是0。可以看到,ArrayBuffer构造函数的参数是所需要的内存大小(单位字节)。

    为了读写这段内容,需要为它指定视图。DataView视图的创建,需要提供ArrayBuffer对象实例作为参数。

    var buf = new ArrayBuffer(32);
    var dataView = new DataView(buf);
    dataView.getUint8(0) // 0

    上面代码对一段32字节的内存,建立DataView视图,然后以不带符号的8位整数格式,读取第一个元素,结果得到0,因为原始内存的ArrayBuffer对象,默认所有位都是0。

    另一种TypedArray视图,与DataView视图的一个区别是,它不是一个构造函数,而是一组构造函数,代表不同的数据格式。

    var buffer = new ArrayBuffer(12);
    
    var x1 = new Int32Array(buffer);
    x1[0] = 1;
    var x2 = new Uint8Array(buffer);
    x2[0]  = 2;
    
    x1[0] // 2

    上面代码对同一段内存,分别建立两种视图:32位带符号整数(Int32Array构造函数)和8位不带符号整数(Uint8Array构造函数)。由于两个视图对应的是同一段内存,一个视图修改底层内存,会影响到另一个视图。

    TypedArray视图的构造函数,除了接受ArrayBuffer实例作为参数,还可以接受正常数组作为参数,直接分配内存生成底层的ArrayBuffer实例,并同时完成对这段内存的赋值。

    var typedArray = new Uint8Array([0,1,2]);
    typedArray.length // 3
    
    typedArray[0] = 5;
    typedArray // [5, 1, 2]

    上面代码使用TypedArray视图的Uint8Array构造函数,新建一个不带符号的8位整数视图。可以看到,Uint8Array直接使用正常数组作为参数,对底层内存的赋值同时完成。

    ArrayBuffer.prototype.byteLength

    ArrayBuffer实例的byteLength属性,返回所分配的内存区域的字节长度。

    var buffer = new ArrayBuffer(32);
    buffer.byteLength
    // 32

    如果要分配的内存区域很大,有可能分配失败(因为没有那么多的连续空余内存),所以有必要检查是否分配成功。

    if (buffer.byteLength === n) {
      // 成功
    } else {
      // 失败
    }

    ArrayBuffer.prototype.slice()

    ArrayBuffer实例有一个slice方法,允许将内存区域的一部分,拷贝生成一个新的ArrayBuffer对象。

    var buffer = new ArrayBuffer(8);
    var newBuffer = buffer.slice(0, 3);

    上面代码拷贝buffer对象的前3个字节(从0开始,到第3个字节前面结束),生成一个新的ArrayBuffer对象。slice方法其实包含两步,第一步是先分配一段新内存,第二步是将原来那个ArrayBuffer对象拷贝过去。

    slice方法接受两个参数,第一个参数表示拷贝开始的字节序号(含该字节),第二个参数表示拷贝截止的字节序号(不含该字节)。如果省略第二个参数,则默认到原ArrayBuffer对象的结尾。

    除了slice方法,ArrayBuffer对象不提供任何直接读写内存的方法,只允许在其上方建立视图,然后通过视图读写。

    ArrayBuffer.isView()

    ArrayBuffer有一个静态方法isView,返回一个布尔值,表示参数是否为ArrayBuffer的视图实例。这个方法大致相当于判断参数,是否为TypedArray实例或DataView实例。

    var buffer = new ArrayBuffer(8);
    ArrayBuffer.isView(buffer) // false
    
    var v = new Int32Array(buffer);
    ArrayBuffer.isView(v) // true

    TypedArray对象

    概述

    ArrayBuffer对象作为内存区域,可以存放多种类型的数据。同一段内存,不同数据有不同的解读方式,这就叫做“视图”(view)。ArrayBuffer有两种视图,一种是TypedArray视图,另一种是DataView视图,两者的区别主要是字节序,前者的数组成员都是同一个数据类型,后者的数组成员可以是不同的数据类型。

    目前,TypedArray对象一共提供9种类型的视图,每一种视图都是一种构造函数。

    Int8Array:8位有符号整数,长度1个字节。
    Uint8Array:8位无符号整数,长度1个字节。
    Uint8ClampedArray:8位无符号整数,长度1个字节,溢出处理不同。
    Int16Array:16位有符号整数,长度2个字节。
    Uint16Array:16位无符号整数,长度2个字节。
    Int32Array:32位有符号整数,长度4个字节。
    Uint32Array:32位无符号整数,长度4个字节。
    Float32Array:32位浮点数,长度4个字节。
    Float64Array:64位浮点数,长度8个字节。

    这9个构造函数生成的对象,统称为TypedArray对象。它们很像正常数组,都有length属性,都能用方括号运算符([])获取单个元素,所有数组的方法,在类型化数组上面都能使用。两者的差异主要在以下方面。

    TypedArray数组的所有成员,都是同一种类型和格式。
    TypedArray数组的成员是连续的,不会有空位。
    Typed化数组成员的默认值为0。比如,new Array(10)返回一个正常数组,里面没有任何成员,只是10个空位;new Uint8Array(10)返回一个类型化数组,里面10个成员都是0。
    TypedArray数组只是一层视图,本身不储存数据,它的数据都储存在底层的ArrayBuffer对象之中,要获取底层对象必须使用buffer属性。

    构造函数

    TypedArray数组提供9种构造函数,用来生成相应类型的数组实例。

    构造函数有多种用法。

    (1)TypedArray(buffer, byteOffset=0, length?)

    同一个ArrayBuffer对象之上,可以根据不同的数据类型,建立多个视图。

    // 创建一个8字节的ArrayBuffer
    var b = new ArrayBuffer(8);
    
    // 创建一个指向b的Int32视图,开始于字节0,直到缓冲区的末尾
    var v1 = new Int32Array(b);
    
    // 创建一个指向b的Uint8视图,开始于字节2,直到缓冲区的末尾
    var v2 = new Uint8Array(b, 2);
    
    // 创建一个指向b的Int16视图,开始于字节2,长度为2
    var v3 = new Int16Array(b, 2, 2);

    上面代码在一段长度为8个字节的内存(b)之上,生成了三个视图:v1、v2和v3。

    视图的构造函数可以接受三个参数:

    第一个参数(必需):视图对应的底层ArrayBuffer对象。
    第二个参数(可选):视图开始的字节序号,默认从0开始。
    第三个参数(可选):视图包含的数据个数,默认直到本段内存区域结束。
    因此,v1、v2和v3是重叠的:v1[0]是一个32位整数,指向字节0~字节3;v2[0]是一个8位无符号整数,指向字节2;v3[0]是一个16位整数,指向字节2~字节3。只要任何一个视图对内存有所修改,就会在另外两个视图上反应出来。

    注意,byteOffset必须与所要建立的数据类型一致,否则会报错。

    var buffer = new ArrayBuffer(8);
    var i16 = new Int16Array(buffer, 1);
    // Uncaught RangeError: start offset of Int16Array should be a multiple of 2

    上面代码中,新生成一个8个字节的ArrayBuffer对象,然后在这个对象的第一个字节,建立带符号的16位整数视图,结果报错。因为,带符号的16位整数需要两个字节,所以byteOffset参数必须能够被2整除。

    如果想从任意字节开始解读ArrayBuffer对象,必须使用DataView视图,因为TypedArray视图只提供9种固定的解读格式。

    (2)TypedArray(length)

    视图还可以不通过ArrayBuffer对象,直接分配内存而生成。

    var f64a = new Float64Array(8);
    f64a[0] = 10;
    f64a[1] = 20;
    f64a[2] = f64a[0] + f64a[1];

    上面代码生成一个8个成员的Float64Array数组(共64字节),然后依次对每个成员赋值。这时,视图构造函数的参数就是成员的个数。可以看到,视图数组的赋值操作与普通数组的操作毫无两样。

    (3)TypedArray(typedArray)

    类型化数组的构造函数,可以接受另一个视图实例作为参数。

    var typedArray = new Int8Array(new Uint8Array(4));

    上面代码中,Int8Array构造函数接受一个Uint8Array实例作为参数。

    注意,此时生成的新数组,只是复制了参数数组的值,对应的底层内存是不一样的。新数组会开辟一段新的内存储存数据,不会在原数组的内存之上建立视图。

    var x = new Int8Array([1, 1]);
    var y = new Int8Array(x);
    x[0] // 1
    y[0] // 1
    
    x[0] = 2;
    y[0] // 1

    上面代码中,数组y是以数组x为模板而生成的,当x变动的时候,y并没有变动。

    如果想基于同一段内存,构造不同的视图,可以采用下面的写法。

    var x = new Int8Array([1, 1]);
    var y = new Int8Array(x.buffer);
    x[0] // 1
    y[0] // 1
    
    x[0] = 2;
    y[0] // 2

    (4)TypedArray(arrayLikeObject)

    构造函数的参数也可以是一个普通数组,然后直接生成TypedArray实例。

    var typedArray = new Uint8Array([1, 2, 3, 4]);
    注意,这时TypedArray视图会重新开辟内存,不会在原数组的内存上建立视图。

    上面代码从一个普通的数组,生成一个8位无符号整数的TypedArray实例。

    TypedArray数组也可以转换回普通数组。

    var normalArray = Array.prototype.slice.call(typedArray);

    数组方法

    普通数组的操作方法和属性,对TypedArray数组完全适用。

    TypedArray.prototype.copyWithin(target, start[, end = this.length])
    TypedArray.prototype.entries()
    TypedArray.prototype.every(callbackfn, thisArg?)
    TypedArray.prototype.fill(value, start=0, end=this.length)
    TypedArray.prototype.filter(callbackfn, thisArg?)
    TypedArray.prototype.find(predicate, thisArg?)
    TypedArray.prototype.findIndex(predicate, thisArg?)
    TypedArray.prototype.forEach(callbackfn, thisArg?)
    TypedArray.prototype.indexOf(searchElement, fromIndex=0)
    TypedArray.prototype.join(separator)
    TypedArray.prototype.keys()
    TypedArray.prototype.lastIndexOf(searchElement, fromIndex?)
    TypedArray.prototype.map(callbackfn, thisArg?)
    TypedArray.prototype.reduce(callbackfn, initialValue?)
    TypedArray.prototype.reduceRight(callbackfn, initialValue?)
    TypedArray.prototype.reverse()
    TypedArray.prototype.slice(start=0, end=this.length)
    TypedArray.prototype.some(callbackfn, thisArg?)
    TypedArray.prototype.sort(comparefn)
    TypedArray.prototype.toLocaleString(reserved1?, reserved2?)
    TypedArray.prototype.toString()
    TypedArray.prototype.values()
    上面所有方法的用法,请参阅数组方法的介绍,这里不再重复了。

    另外,TypedArray数组与普通数组一样,部署了Iterator接口,所以可以被遍历。

    let ui8 = Uint8Array.of(0, 1, 2);
    for (let byte of ui8) {
      console.log(byte);
    }
    // 0
    // 1
    // 2

    字节序

    字节序指的是数值在内存中的表示方式。

    var buffer = new ArrayBuffer(16);
    var int32View = new Int32Array(buffer);
    
    for (var i = 0; i < int32View.length; i++) {
      int32View[i] = i * 2;
    }

    上面代码生成一个16字节的ArrayBuffer对象,然后在它的基础上,建立了一个32位整数的视图。由于每个32位整数占据4个字节,所以一共可以写入4个整数,依次为0,2,4,6。

    如果在这段数据上接着建立一个16位整数的视图,则可以读出完全不一样的结果。

    var int16View = new Int16Array(buffer);
    
    for (var i = 0; i < int16View.length; i++) {
      console.log("Entry " + i + ": " + int16View[i]);
    }
    // Entry 0: 0
    // Entry 1: 0
    // Entry 2: 2
    // Entry 3: 0
    // Entry 4: 4
    // Entry 5: 0
    // Entry 6: 6
    // Entry 7: 0

    由于每个16位整数占据2个字节,所以整个ArrayBuffer对象现在分成8段。然后,由于x86体系的计算机都采用小端字节序(little endian),相对重要的字节排在后面的内存地址,相对不重要字节排在前面的内存地址,所以就得到了上面的结果。

    比如,一个占据四个字节的16进制数0x12345678,决定其大小的最重要的字节是“12”,最不重要的是“78”。小端字节序将最不重要的字节排在前面,储存顺序就是78563412;大端字节序则完全相反,将最重要的字节排在前面,储存顺序就是12345678。目前,所有个人电脑几乎都是小端字节序,所以TypedArray数组内部也采用小端字节序读写数据,或者更准确的说,按照本机操作系统设定的字节序读写数据。

    这并不意味大端字节序不重要,事实上,很多网络设备和特定的操作系统采用的是大端字节序。这就带来一个严重的问题:如果一段数据是大端字节序,TypedArray数组将无法正确解析,因为它只能处理小端字节序!为了解决这个问题,JavaScript引入DataView对象,可以设定字节序,下文会详细介绍。

    下面是另一个例子。

    // 假定某段buffer包含如下字节 [0x02, 0x01, 0x03, 0x07]
    var buffer = new ArrayBuffer(4);
    var v1 = new Uint8Array(buffer);
    v1[0] = 2;
    v1[1] = 1;
    v1[2] = 3;
    v1[3] = 7;
    
    var uInt16View = new Uint16Array(buffer);
    
    // 计算机采用小端字节序
    // 所以头两个字节等于258
    if (uInt16View[0] === 258) {
      console.log('OK'); // "OK"
    }
    
    // 赋值运算
    uInt16View[0] = 255;    // 字节变为[0xFF, 0x00, 0x03, 0x07]
    uInt16View[0] = 0xff05; // 字节变为[0x05, 0xFF, 0x03, 0x07]
    uInt16View[1] = 0x0210; // 字节变为[0x05, 0xFF, 0x10, 0x02]

    下面的函数可以用来判断,当前视图是小端字节序,还是大端字节序。

    const BIG_ENDIAN = Symbol('BIG_ENDIAN');
    const LITTLE_ENDIAN = Symbol('LITTLE_ENDIAN');
    
    function getPlatformEndianness() {
      let arr32 = Uint32Array.of(0x12345678);
      let arr8 = new Uint8Array(arr32.buffer);
      switch ((arr8[0]*0x1000000) + (arr8[1]*0x10000) + (arr8[2]*0x100) + (arr8[3])) {
        case 0x12345678:
          return BIG_ENDIAN;
        case 0x78563412:
          return LITTLE_ENDIAN;
        default:
          throw new Error('Unknown endianness');
      }
    }

    总之,与普通数组相比,TypedArray数组的最大优点就是可以直接操作内存,不需要数据类型转换,所以速度快得多。

    BYTES_PER_ELEMENT属性

    每一种视图的构造函数,都有一个BYTES_PER_ELEMENT属性,表示这种数据类型占据的字节数。

    Int8Array.BYTES_PER_ELEMENT // 1
    Uint8Array.BYTES_PER_ELEMENT // 1
    Int16Array.BYTES_PER_ELEMENT // 2
    Uint16Array.BYTES_PER_ELEMENT // 2
    Int32Array.BYTES_PER_ELEMENT // 4
    Uint32Array.BYTES_PER_ELEMENT // 4
    Float32Array.BYTES_PER_ELEMENT // 4
    Float64Array.BYTES_PER_ELEMENT // 8
    这个属性在TypedArray实例上也能获取,即有TypedArray.prototype.BYTES_PER_ELEMENT。

    ArrayBuffer与字符串的互相转换

    ArrayBuffer转为字符串,或者字符串转为ArrayBuffer,有一个前提,即字符串的编码方法是确定的。假定字符串采用UTF-16编码(JavaScript的内部编码方式),可以自己编写转换函数。

    // ArrayBuffer转为字符串,参数为ArrayBuffer对象
    function ab2str(buf) {
      return String.fromCharCode.apply(null, new Uint16Array(buf));
    }
    
    // 字符串转为ArrayBuffer对象,参数为字符串
    function str2ab(str) {
      var buf = new ArrayBuffer(str.length * 2); // 每个字符占用2个字节
      var bufView = new Uint16Array(buf);
      for (var i = 0, strLen = str.length; i < strLen; i++) {
        bufView[i] = str.charCodeAt(i);
      }
      return buf;
    }

    溢出

    不同的视图类型,所能容纳的数值范围是确定的。超出这个范围,就会出现溢出。比如,8位视图只能容纳一个8位的二进制值,如果放入一个9位的值,就会溢出。

    TypedArray数组的溢出处理规则,简单来说,就是抛弃溢出的位,然后按照视图类型进行解释。

    var uint8 = new Uint8Array(1);
    
    uint8[0] = 256;
    uint8[0] // 0
    
    uint8[0] = -1;
    uint8[0] // 255

    上面代码中,uint8是一个8位视图,而256的二进制形式是一个9位的值100000000,这时就会发生溢出。根据规则,只会保留后8位,即00000000。uint8视图的解释规则是无符号的8位整数,所以00000000就是0。

    负数在计算机内部采用“2的补码”表示,也就是说,将对应的正数值进行否运算,然后加1。比如,-1对应的正值是1,进行否运算以后,得到11111110,再加上1就是补码形式11111111。uint8按照无符号的8位整数解释11111111,返回结果就是255。

    一个简单转换规则,可以这样表示。

    正向溢出(overflow):当输入值大于当前数据类型的最大值,结果等于当前数据类型的最小值加上余值,再减去1。
    负向溢出(underflow):当输入值小于当前数据类型的最小值,结果等于当前数据类型的最大值减去余值,再加上1。
    请看下面的例子。

    var int8 = new Int8Array(1);
    
    int8[0] = 128;
    int8[0] // -128
    
    int8[0] = -129;
    int8[0] // 127

    上面例子中,int8是一个带符号的8位整数视图,它的最大值是127,最小值是-128。输入值为128时,相当于正向溢出1,根据“最小值加上余值,再减去1”的规则,就会返回-128;输入值为-129时,相当于负向溢出1,根据“最大值减去余值,再加上1”的规则,就会返回127。

    Uint8ClampedArray视图的溢出规则,与上面的规则不同。它规定,凡是发生正向溢出,该值一律等于当前数据类型的最大值,即255;如果发生负向溢出,该值一律等于当前数据类型的最小值,即0。

    var uint8c = new Uint8ClampedArray(1);
    
    uint8c[0] = 256;
    uint8c[0] // 255
    
    uint8c[0] = -1;
    uint8c[0] // 0

    上面例子中,uint8C是一个Uint8ClampedArray视图,正向溢出时都返回255,负向溢出都返回0。

    TypedArray.prototype.buffer

    TypedArray实例的buffer属性,返回整段内存区域对应的ArrayBuffer对象。该属性为只读属性。

    var a = new Float32Array(64);
    var b = new Uint8Array(a.buffer);

    上面代码的a视图对象和b视图对象,对应同一个ArrayBuffer对象,即同一段内存。

    TypedArray.prototype.byteLength,TypedArray.prototype.byteOffset
    byteLength属性返回TypedArray数组占据的内存长度,单位为字节。byteOffset属性返回TypedArray数组从底层ArrayBuffer对象的哪个字节开始。这两个属性都是只读属性。

    var b = new ArrayBuffer(8);
    
    var v1 = new Int32Array(b);
    var v2 = new Uint8Array(b, 2);
    var v3 = new Int16Array(b, 2, 2);
    
    v1.byteLength // 8
    v2.byteLength // 6
    v3.byteLength // 4
    
    v1.byteOffset // 0
    v2.byteOffset // 2
    v3.byteOffset // 2

    TypedArray.prototype.length

    length属性表示TypedArray数组含有多少个成员。注意将byteLength属性和length属性区分,前者是字节长度,后者是成员长度。

    var a = new Int16Array(8);
    
    a.length // 8
    a.byteLength // 16
    TypedArray.prototype.set()

    TypedArray数组的set方法用于复制数组(正常数组或TypedArray数组),也就是将一段内容完全复制到另一段内存。

    var a = new Uint8Array(8);
    var b = new Uint8Array(8);
    
    b.set(a);

    上面代码复制a数组的内容到b数组,它是整段内存的复制,比一个个拷贝成员的那种复制快得多。set方法还可以接受第二个参数,表示从b对象哪一个成员开始复制a对象。

    var a = new Uint16Array(8);
    var b = new Uint16Array(10);
    
    b.set(a, 2)

    上面代码的b数组比a数组多两个成员,所以从b[2]开始复制。

    TypedArray.prototype.subarray()

    subarray方法是对于TypedArray数组的一部分,再建立一个新的视图。

    var a = new Uint16Array(8);
    var b = a.subarray(2,3);
    
    a.byteLength // 16
    b.byteLength // 2

    subarray方法的第一个参数是起始的成员序号,第二个参数是结束的成员序号(不含该成员),如果省略则包含剩余的全部成员。所以,上面代码的a.subarray(2,3),意味着b只包含a[2]一个成员,字节长度为2。

    TypedArray.prototype.slice()
    TypeArray实例的slice方法,可以返回一个指定位置的新的TypedArray实例。
    
    let ui8 = Uint8Array.of(0, 1, 2);
    ui8.slice(-1)
    // Uint8Array [ 2 ]

    上面代码中,ui8是8位无符号整数数组视图的一个实例。它的slice方法可以从当前视图之中,返回一个新的视图实例。

    slice方法的参数,表示原数组的具体位置,开始生成新数组。负值表示逆向的位置,即-1为倒数第一个位置,-2表示倒数第二个位置,以此类推。

    TypedArray.of()

    TypedArray数组的所有构造函数,都有一个静态方法of,用于将参数转为一个TypedArray实例。

    Float32Array.of(0.151, -8, 3.7)
    // Float32Array [ 0.151, -8, 3.7 ]

    TypedArray.from()

    静态方法from接受一个可遍历的数据结构(比如数组)作为参数,返回一个基于这个结构的TypedArray实例。

    Uint16Array.from([0, 1, 2])
    // Uint16Array [ 0, 1, 2 ]

    这个方法还可以将一种TypedArray实例,转为另一种。

    var ui16 = Uint16Array.from(Uint8Array.of(0, 1, 2));
    ui16 instanceof Uint16Array // true

    from方法还可以接受一个函数,作为第二个参数,用来对每个元素进行遍历,功能类似map方法。

    Int8Array.of(127, 126, 125).map(x => 2 * x)
    // Int8Array [ -2, -4, -6 ]
    
    Int16Array.from(Int8Array.of(127, 126, 125), x => 2 * x)
    // Int16Array [ 254, 252, 250 ]

    上面的例子中,from方法没有发生溢出,这说明遍历是针对新生成的16位整数数组,而不是针对原来的8位整数数组。也就是说,from会将第一个参数指定的TypedArray数组,拷贝到另一段内存之中(占用内存从3字节变为6字节),然后再进行处理。

    复合视图

    由于视图的构造函数可以指定起始位置和长度,所以在同一段内存之中,可以依次存放不同类型的数据,这叫做“复合视图”。

    var buffer = new ArrayBuffer(24);
    
    var idView = new Uint32Array(buffer, 0, 1);
    var usernameView = new Uint8Array(buffer, 4, 16);
    var amountDueView = new Float32Array(buffer, 20, 1);

    上面代码将一个24字节长度的ArrayBuffer对象,分成三个部分:

    字节0到字节3:1个32位无符号整数
    字节4到字节19:16个8位整数
    字节20到字节23:1个32位浮点数
    这种数据结构可以用如下的C语言描述:

    struct someStruct {
      unsigned long id;
      char username[16];
      float amountDue;
    };

    DataView视图

    如果一段数据包括多种类型(比如服务器传来的HTTP数据),这时除了建立ArrayBuffer对象的复合视图以外,还可以通过DataView视图进行操作。

    DataView视图提供更多操作选项,而且支持设定字节序。本来,在设计目的上,ArrayBuffer对象的各种TypedArray视图,是用来向网卡、声卡之类的本机设备传送数据,所以使用本机的字节序就可以了;而DataView视图的设计目的,是用来处理网络设备传来的数据,所以大端字节序或小端字节序是可以自行设定的。

    DataView视图本身也是构造函数,接受一个ArrayBuffer对象作为参数,生成视图。

    DataView(ArrayBuffer buffer [, 字节起始位置 [, 长度]]);
    下面是一个例子。

    var buffer = new ArrayBuffer(24);
    var dv = new DataView(buffer);

    DataView实例有以下属性,含义与TypedArray实例的同名方法相同。

    DataView.prototype.buffer:返回对应的ArrayBuffer对象
    DataView.prototype.byteLength:返回占据的内存字节长度
    DataView.prototype.byteOffset:返回当前视图从对应的ArrayBuffer对象的哪个字节开始
    DataView实例提供8个方法读取内存。

    getInt8:读取1个字节,返回一个8位整数。
    getUint8:读取1个字节,返回一个无符号的8位整数。
    getInt16:读取2个字节,返回一个16位整数。
    getUint16:读取2个字节,返回一个无符号的16位整数。
    getInt32:读取4个字节,返回一个32位整数。
    getUint32:读取4个字节,返回一个无符号的32位整数。
    getFloat32:读取4个字节,返回一个32位浮点数。
    getFloat64:读取8个字节,返回一个64位浮点数。
    这一系列get方法的参数都是一个字节序号(不能是负数,否则会报错),表示从哪个字节开始读取。

    var buffer = new ArrayBuffer(24);
    var dv = new DataView(buffer);
    
    // 从第1个字节读取一个8位无符号整数
    var v1 = dv.getUint8(0);
    
    // 从第2个字节读取一个16位无符号整数
    var v2 = dv.getUint16(1);
    
    // 从第4个字节读取一个16位无符号整数
    var v3 = dv.getUint16(3);

    上面代码读取了ArrayBuffer对象的前5个字节,其中有一个8位整数和两个十六位整数。

    如果一次读取两个或两个以上字节,就必须明确数据的存储方式,到底是小端字节序还是大端字节序。默认情况下,DataView的get方法使用大端字节序解读数据,如果需要使用小端字节序解读,必须在get方法的第二个参数指定true。

    // 小端字节序
    var v1 = dv.getUint16(1, true);
    
    // 大端字节序
    var v2 = dv.getUint16(3, false);
    
    // 大端字节序
    var v3 = dv.getUint16(3);

    DataView视图提供8个方法写入内存。

    setInt8:写入1个字节的8位整数。
    setUint8:写入1个字节的8位无符号整数。
    setInt16:写入2个字节的16位整数。
    setUint16:写入2个字节的16位无符号整数。
    setInt32:写入4个字节的32位整数。
    setUint32:写入4个字节的32位无符号整数。
    setFloat32:写入4个字节的32位浮点数。
    setFloat64:写入8个字节的64位浮点数。
    这一系列set方法,接受两个参数,第一个参数是字节序号,表示从哪个字节开始写入,第二个参数为写入的数据。对于那些写入两个或两个以上字节的方法,需要指定第三个参数,false或者undefined表示使用大端字节序写入,true表示使用小端字节序写入。

    // 在第1个字节,以大端字节序写入值为25的32位整数
    dv.setInt32(0, 25, false);
    
    // 在第5个字节,以大端字节序写入值为25的32位整数
    dv.setInt32(4, 25);
    
    // 在第9个字节,以小端字节序写入值为2.5的32位浮点数
    dv.setFloat32(8, 2.5, true);
    如果不确定正在使用的计算机的字节序,可以采用下面的判断方式。
    
    var littleEndian = (function() {
      var buffer = new ArrayBuffer(2);
      new DataView(buffer).setInt16(0, 256, true);
      return new Int16Array(buffer)[0] === 256;
    })();

    如果返回true,就是小端字节序;如果返回false,就是大端字节序。

    二进制数组的应用

    大量的Web API用到了ArrayBuffer对象和它的视图对象。

    AJAX

    传统上,服务器通过AJAX操作只能返回文本数据,即responseType属性默认为text。XMLHttpRequest第二版XHR2允许服务器返回二进制数据,这时分成两种情况。如果明确知道返回的二进制数据类型,可以把返回类型(responseType)设为arraybuffer;如果不知道,就设为blob。

    var xhr = new XMLHttpRequest();
    xhr.open('GET', someUrl);
    xhr.responseType = 'arraybuffer';
    
    xhr.onload = function () {
      var let arrayBuffer = xhr.response;
      // ···
    };
    
    xhr.send();

    如果知道传回来的是32位整数,可以像下面这样处理。

    xhr.onreadystatechange = function () {
      if (req.readyState === 4 ) {
        var arrayResponse = xhr.response;
        var dataView = new DataView(arrayResponse);
        var ints = new Uint32Array(dataView.byteLength / 4);
    
        xhrDiv.style.backgroundColor = "#00FF00";
        xhrDiv.innerText = "Array is " + ints.length + "uints long";
      }
    }

    Canvas

    网页Canvas元素输出的二进制像素数据,就是类型化数组。

    var canvas = document.getElementById('myCanvas');
    var ctx = canvas.getContext('2d');
    
    var imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
    var uint8ClampedArray = imageData.data;

    需要注意的是,上面代码的typedArray虽然是一个类型化数组,但是它的视图类型是一种针对Canvas元素的专有类型Uint8ClampedArray。这个视图类型的特点,就是专门针对颜色,把每个字节解读为无符号的8位整数,即只能取值0~255,而且发生运算的时候自动过滤高位溢出。这为图像处理带来了巨大的方便。

    举例来说,如果把像素的颜色值设为Uint8Array类型,那么乘以一个gamma值的时候,就必须这样计算:

    u8[i] = Math.min(255, Math.max(0, u8[i] * gamma));

    因为Uint8Array类型对于大于255的运算结果(比如0xFF+1),会自动变为0x00,所以图像处理必须要像上面这样算。这样做很麻烦,而且影响性能。如果将颜色值设为Uint8ClampedArray类型,计算就简化许多。

    pixels[i] *= gamma;

    Uint8ClampedArray类型确保将小于0的值设为0,将大于255的值设为255。注意,IE 10不支持该类型。

    WebSocket

    WebSocket可以通过ArrayBuffer,发送或接收二进制数据。

    var socket = new WebSocket('ws://127.0.0.1:8081');
    socket.binaryType = 'arraybuffer';
    
    // Wait until socket is open
    socket.addEventListener('open', function (event) {
      // Send binary data
      var typedArray = new Uint8Array(4);
      socket.send(typedArray.buffer);
    });
    
    // Receive binary data
    socket.addEventListener('message', function (event) {
      var arrayBuffer = event.data;
      // ···
    });

    Fetch API

    Fetch API取回的数据,就是ArrayBuffer对象。

    fetch(url)
    .then(function(request){
      return request.arrayBuffer()
    })
    .then(function(arrayBuffer){
      // ...
    });

    File API

    如果知道一个文件的二进制数据类型,也可以将这个文件读取为ArrayBuffer对象。

    var fileInput = document.getElementById('fileInput');
    var file = fileInput.files[0];
    var reader = new FileReader();
    reader.readAsArrayBuffer(file);
    reader.onload = function () {
      var arrayBuffer = reader.result;
      // ···
    };

    下面以处理bmp文件为例。假定file变量是一个指向bmp文件的文件对象,首先读取文件。

    var reader = new FileReader();
    reader.addEventListener("load", processimage, false);
    reader.readAsArrayBuffer(file);

    然后,定义处理图像的回调函数:先在二进制数据之上建立一个DataView视图,再建立一个bitmap对象,用于存放处理后的数据,最后将图像展示在canvas元素之中。

    function processimage(e) {
      var buffer = e.target.result;
      var datav = new DataView(buffer);
      var bitmap = {};
      // 具体的处理步骤
    }

    具体处理图像数据时,先处理bmp的文件头。具体每个文件头的格式和定义,请参阅有关资料。

    bitmap.fileheader = {};
    bitmap.fileheader.bfType = datav.getUint16(0, true);
    bitmap.fileheader.bfSize = datav.getUint32(2, true);
    bitmap.fileheader.bfReserved1 = datav.getUint16(6, true);
    bitmap.fileheader.bfReserved2 = datav.getUint16(8, true);
    bitmap.fileheader.bfOffBits = datav.getUint32(10, true);

    接着处理图像元信息部分。

    bitmap.infoheader = {};
    bitmap.infoheader.biSize = datav.getUint32(14, true);
    bitmap.infoheader.biWidth = datav.getUint32(18, true);
    bitmap.infoheader.biHeight = datav.getUint32(22, true);
    bitmap.infoheader.biPlanes = datav.getUint16(26, true);
    bitmap.infoheader.biBitCount = datav.getUint16(28, true);
    bitmap.infoheader.biCompression = datav.getUint32(30, true);
    bitmap.infoheader.biSizeImage = datav.getUint32(34, true);
    bitmap.infoheader.biXPelsPerMeter = datav.getUint32(38, true);
    bitmap.infoheader.biYPelsPerMeter = datav.getUint32(42, true);
    bitmap.infoheader.biClrUsed = datav.getUint32(46, true);
    bitmap.infoheader.biClrImportant = datav.getUint32(50, true);

    最后处理图像本身的像素信息。

    var start = bitmap.fileheader.bfOffBits;
    bitmap.pixels = new Uint8Array(buffer, start);

    至此,图像文件的数据全部处理完成。下一步,可以根据需要,进行图像变形,或者转换格式,或者展示在Canvas网页元素之中。

    展开全文
  • 二进制数的运算方法

    万次阅读 多人点赞 2017-08-29 14:12:13
    1.二进制数的算术运算 二进制数的算术运算包括:加、减、乘、除四则运算,下面分别予以介绍。 (1)二进制数的加法 根据“逢二进一”规则,二进制数加法的法则为: 0+0=0 0+1=1+0=1 1+1=0 (进位为1)...

    1.二进制数的算术运算
    二进制数的算术运算包括:加、减、乘、除四则运算,下面分别予以介绍。

    (1)二进制数的加法

      根据“逢二进一”规则,二进制数加法的法则为:
      0+0=0
      0+1=1+0=1
      1+1=0 (进位为1) 
      1+1+1=1 (进位为1)
    
      例如:1110和1011相加过程如下:
    

    在这里插入图片描述

      (2)二进制数的减法
    
      根据“借一有二”的规则,二进制数减法的法则为:
    
      0-0=0
      1-1=0
      1-0=1
      0-1=1 (借位为1)
    
      例如:1101减去1011的过程如下:
    

    在这里插入图片描述

      (3)二进制数的乘法
    
      二进制数乘法过程可仿照十进制数乘法进行。但由于二进制数只有0或1两种可能的乘数位,导致二进制乘法更为简单。二进制数乘法的法则为:
    
      0×0=0
      0×1=1×0=0
      1×1=1
    
      例如:1001和1010相乘的过程如下:
    

    这里写图片描述

      由低位到高位,用乘数的每一位去乘被乘数,若乘数的某一位为1,则该次部分积为被乘数;若乘数的某一位为0,则该次部分积为0。某次部分积的最低位必须和本位乘数对齐,所有部分积相加的结果则为相乘得到的乘积。
    
      (4)二进制数的除法
    
      二进制数除法与十进制数除法很类似。可先从被除数的最高位开始,将被除数(或中间余数)与除数相比较,若被除数(或中间余数)大于除数,则用被除数(或中间余数)减去除数,商为1,并得相减之后的中间余数,否则商为0。再将被除数的下一位移下补充到中间余数的末位,重复以上过程,就可得到所要求的各位商数和最终的余数。
    
      例如:100110÷110的过程如下:
    

    这里写图片描述

      所以,100110÷110=110余10。
    

    2.二进制数的逻辑运算
    二进制数的逻辑运算包括逻辑加法(“或”运算)、逻辑乘法(“与”运算)、逻辑否定(“非”运算)和逻辑“异或”运算。

      (1)逻辑“或”运算
    
      又称为逻辑加,可用符号“+”或“∨”来表示。逻辑“或”运算的规则如下:
    
      0+0=0或0∨0=0
      0+1=1或0∨1=1
      1+0=1或1∨0=1
      1+1=1或1∨1=1
    
      
      可见,两个相“或”的逻辑变量中,只要有一个为1,“或”运算的结果就为1。仅当两个变量都为0时,或运算的结果才为0。计算时,要特别注意和算术运算的加法加以区别。
    
      (2)逻辑“与”运算
    
      又称为逻辑乘,常用符号“×”或“· ”或“∧”表示。“与”运算遵循如下运算规则:
    
      0×1=0或0·1=0或0∧1=0
      1×0=0或1·0=0或1∧0=0
      1×1=1或1·1=1或1∧1=1
    
      可见,两个相“与”的逻辑变量中,只要有一个为0,“与”运算的结果就为0。仅当两个变量都为1时,“与”运算的结果才为1。
    
      (3)逻辑“非”运算
    
      又称为逻辑否定,实际上就是将原逻辑变量的状态求反,其运算规则如下:
    
    
      可见,在变量的上方加一横线表示“非”。逻辑变量为0时,“非”运算的结果为1。逻辑变量为1时,“非”运算的结果为0。
    
      (4)逻辑“异或”运算 
      “异或”运算,常用符号“”或“”来表示,其运算规则为:
    
      00=0 或 00=0
      01=1 或 01=1
      10=1 或 10=1
      11=0 或 11=0
    
      可见:两个相“异或”的逻辑运算变量取值相同时,“异或”的结果为0。取值相异时,“异或”的结果为1
    
    展开全文
  • 二进制

    2017-08-03 21:34:00
    二进制是计算技术中广泛采用的一种数制。二进制数据是用0和1两个数码来表示的数。它的基数为2,进位规则是“逢二进一”,借位规则是“借一当二”,由18世纪德国数理哲学大师莱布尼兹发现。当前的计算机系统使用的...

       二进制是计算技术中广泛采用的一种数制。二进制数据是用0和1两个数码来表示的数。它的基数为2,进位规则是“逢二进一”,借位规则是“借一当二”,由18世纪德国数理哲学大师莱布尼兹发现。当前的计算机系统使用的基本上是二进制系统,数据在计算机中主要是以补码的形式存储的。计算机中的二进制则是一个非常微小的开关,用1来表示“开”,0来表示“关”。

    基本概念

    ​二进制是计算技术中广泛采用的一种数制。二进制数据是用0和1两个数码来表示的数。它的基数为2,进位规则是“逢二进一”,借位规则是“借一当二”,由18世纪德国数理哲学大师莱布尼兹发现。当前的计算机系统使用的基本上是二进制系统。

    数据在计算机中主要是以补码的形式存储的。计算机中的二进制则是一个非常微小的开关,用“开”来表示1,“关”来表示0。

    20世纪被称作第三次科技革命的重要标志之一的计算机的发明与应用,因为数字计算机只能识别处理由‘0’.‘1’符号串组成的代码。其运算模式正是二进制。19世纪爱尔兰逻辑学家乔治布尔对逻辑命题的思考过程转化为对符号"0''.''1''的某种代数演算,二进制是逢2进位的进位制。0、1是基本算符。因为它只使用0、1两个数字符号,非常简单方便,易于用电子方式实现。

    简介

    20世纪被称作第三次科技革命的重要标志之一的计算机的发明与应用,因为数字计算机只能识别处理由‘0’.‘1’符号串组成的代码。其运算模式正是二进制。19世纪爱尔兰逻辑学家乔治布尔对逻辑命题的思考过程转化为对符号"0''.''1''的某种代数演算,二进制是逢2进位的进位制。0、1是基本算符。因为它只使用0、1两个数字符号,非常简单方便,易于用电子方式实现。

    二进制和十六进制八进制一样,都以二的来进位的。

    主要特点

     

    优点

     

    数字装置简单可靠,所用元件少;

    只有两个数码0和1,因此它的每一位数都可用任何具有两个不同稳定状态的元件来表示;

    基本运算规则简单,运算操作方便。

     

    缺点

    用二进制表示一个数时,位数多。因此实际使用中多采用送入数字系统前用十进制,送入机器后再转换成二进制数,让数字系统进行运算,运算结束后再将二进制转换为十进制供人们阅读。

    二进制和十六进制的互相转换比较重要。不过这二者的转换却不用计算,每个C,C++程序员都能做到看见二进制数,直接就能转换为十六进制数,反之亦然。

    我们也一样,只要学完这一小节,就能做到。

    首先我们来看一个二进制数:1111,它是多少呢?

    你可能还要这样计算:1 * 2^0 + 1 * 2^1 + 1 * 2^2 + 1 * 2^3 = 1 * 1 + 1 * 2 + 1 * 4 + 1 * 8 = 15。

    然而,由于1111才4位,所以我们必须直接记住它每一位的权值,并且是从高位往低位记,:8、4、2、1。即,最高位的权值为2^3 = 8,然后依次是 2^2 = 4,2^1=2, 2^0 = 1。

    记住8421,对于任意一个4位的二进制数,我们都可以很快算出它对应的10进制值。

    下面列出四位二进制数 xxxx 所有可能的值(中间略过部分)

    仅4位的2进制数快速计算方法 十进制值 十六进值

    1111 = 8 + 4 + 2 + 1 = 15 F

    1110 = 8 + 4 + 2 + 0 = 14 E

    1101 = 8 + 4 + 0 + 1 = 13 D

    1100 = 8 + 4 + 0 + 0 = 12 C

    1011 = 8 + 0 + 2+ 1 = 11 B

    1010 = 8 + 0 + 2 + 0 = 10 A

    1001 = 8 + 0 + 0 + 1 = 9 9

    ....

    0001 = 0 + 0 + 0 + 1 = 1

    0000 = 0 + 0 + 0 + 0 = 0 0

    二进制数要转换为十六进制,就是以4位一段,分别转换为十六进制。

    如(上行为二制数,下面为对应的十六进制):

    1111 1101 , 1010 0101 , 1001 1011

    F D , A 5 , 9 B

    反过来,当我们看到 FD时,如何迅速将它转换为二进制数呢?

    先转换F:

    看到F,我们需知道它是15(可能你还不熟悉A~F这六个数),然后15如何用8421凑呢?应该是8 + 4 + 2 + 1,所以四位全为1 :1111。

    接着转换 D:

    看到D,知道它是13,13如何用8421凑呢?应该是:8 + 4+0+ 1,即:1101。

    所以,FD转换为二进制数,为: 1111 1101

    由于十六进制转换成二进制相当直接,所以,我们需要将一个十进制数转换成2进制数时,也可以先转换成16进制,然后再转换成2进制。

    比如,十进制数 1234转换成二制数,如果要一直除以2,直接得到2进制数,需要计算较多次数。所以我们可以先除以16,得到16进制数:

    被除数 计算过程  余数

    1234 1234/16 77 2

    77 77/16 4 13 (D)

    4 4/16 0 4

    结果16进制为: 0x4D2

    然后我们可直接写出0x4D2的二进制形式: 0100 1101 0010。

    其中对映关系为:

    0100 -- 4

    1101 -- D

    0010 -- 2

    同样,如果一个二进制数很长,我们需要将它转换成10进制数时,除了前面学过的方法是,我们还可以先将这个二进制转换成16进制,然后再转换为10进制。

    下面举例一个int类型的二进制数:

    01101101 11100101 10101111 00011011

    我们按四位一组转换为16进制: 6D E5 AF 1B

    折叠编辑本段基本运算

    二进制数据的算术运算的基本规律和十进制数的运算十分相似。最常用的是加法运算和乘法运算。

    折叠二进制加法

    有四种情况: 0+0=0

    0+1=1

    1+0=1

    1+1=10

    ps:0 进位为1

    【例1103】求 (1101)2+(1011)2 的和

    解:

    1 1 0 1

    +1 0 1 1

    -------------------

    1 1 0 0 0

    折叠二进制乘法

    有四种情况: 0×0=0

    1×0=0

    0×1=0

    1×1=1

    【例1104】求 (1110)2 乘(101)2 之积

    解:

    1 1 1 0

    × 1 0 1

    -----------------------

    1 1 1 0

    0 0 0 0

    1 1 1 0

    -------------------------

    1 0 0 0 1 1 0

    (这些计算就跟十进制的加或者乘法相同,只是进位的数不一样而已,十进制的是到十才进位这里是到2就进了)

    3.二进制减法

    0-0=0,1-0=1,1-1=0,10-1=1。

    4.二进制除法

    0÷1=0,1÷1=1。[1-2]

    5.二进制拈加法

    拈加法二进制加减乘除外的一种特殊算法。

    拈加法运算与进行加法类似,但不需要做进位。此算法在博弈论(Game Theory)中被广泛利用

    计算机中的十进制小数转换二进制  

    计算机中的十进制小数用二进制通常是用乘二取整法来获得的。

    比如0.65换算成二进制就是:

    0.65 * 2 = 1.3 取1,留下0.3继续乘二取整

    0.3 * 2 = 0.6 取0, 留下0.6继续乘二取整

    0.6 * 2 = 1.2 取1,留下0.2继续乘二取整

    0.2 * 2 = 0.4 取0, 留下0.4继续乘二取整

    0.4 * 2 = 0.8 取0, 留下0.8继续乘二取整

    0.8 * 2 = 1.6 取1, 留下0.6继续乘二取整

    0.6 * 2 = 1.2 取1,留下0.2继续乘二取整

    .......

    一直循环,直到达到精度限制才停止(所以,计算机保存的小数一般会有误差,所以在编程中,要想比较两个小数是否相等,只能比较某个精度范围内是否相等。)。这时,十进制的0.65,用二进制就可以表示为:1010011。

    还值得一提的是,在目前的计算机中,除了十进制是有符号的外,其他如二进制、八进制、16进制都是无符号的。

    折叠编辑本段进制转换

    十进制数转换为二进制数、八进制数、十六进制数的方法:

    二进制数、八进制数、十六进制数转换为十进制数的方法:按权展开求和法

    折叠二进制与十进制间的相互转换

    (1)二进制转十进制

    方法:“按权展开求和”

    例: (1011.01)2 =(1×2^3+0×2^2+1×2^1+1×2^0+0×2^(-1)+1×2^(-2) )10

    =(8+0+2+1+0+0.25)10

    =(11.25)10

    规律:个位上的数字的次数是0,十位上的数字的次数是1,......,依次递增,而十

    分位的数字的次数是-1,百分位上数字的次数是-2,......,依次递减。

    注意:不是任何一个十进制小数都能转换成有限位的二进制数。

    (2)十进制转二进制

    · 十进制整数转二进制数:“除以2取余,逆序排列”(除二取余法)

    例: (89)10 =(1011001)2

    89÷2 ……1

    44÷2 ……0

    22÷2 ……0

    11÷2 ……1

    5÷2 ……1

    2÷2 ……0

    1

    · 十进制小数转二进制数:“乘以2取整,顺序排列”(乘2取整法)

    例: (0.625)10= (0.101)2

    0.625X2=1.25 ……1

    0.25 X2=0.50 ……0

    0.50 X2=1.00 ……1

    十进制1至100的二进制表示

    0=0

    1=1

    2=10

    3=11

    4=100

    5=101

    6=110

    7=111

    8=1000

    9=1001

    10=1010

    11=1011

    12=1100

    13=1101

    14=1110

    15=1111

    16=10000

    17=10001

    18=10010

    19=10011

    20=10100

    21=10101

    22=10110

    23=10111

    24=11000

    25=11001

    26=11010

    27=11011

    28=11100

    29=11101

    30=11110

    31=11111

    32=100000

    33=100001

    34=100010

    35=100011

    36=100100

    37=100101

    38=100110

    39=100111

    40=101000

    41=101001

    42=101010

    43=101011

    44=101100

    45=101101

    46=101110

    47=101111

    48=110000

    49=110001

    50=110010

    51=110011

    52=110100

    53=110101

    54=110110

    55=110111

    56=111000

    57=111001

    58=111010

    59=111011

    60=111100

    61=111101

    62=111110

    63=111111

    64=1000000

    65=1000001

    66=1000010

    67=1000011

    68=1000100

    69=1000101

    70=1000110

    71=1000111

    72=1001000

    73=1001001

    74=1001010

    75=1001011

    76=1001100

    77=1001101

    78=1001110

    79=1001111

    80=1010000

    81=1010001

    82=1010010

    83=1010011

    84=1010100

    85=1010101

    86=1010110

    87=1010111

    88=1011000

    89=1011001

    90=1011010

    91=1011011

    92=1011100

    93=1011101

    94=1011110

    95=1011111

    96=1100000

    97=1100001

    98=1100010

    99=1100011

    100=1100100

    折叠八进制与二进制的转换

    二进制数转换成八进制数:从小数点开始,整数部分向左、小数部分向右,每3位为一组用一位八进制数的数字表示,不足3位的要用“0”补足3位,就得到一个八进制数。

    八进制数转换成二进制数:把每一个八进制数转换成3位的二进制数,就得到一个二进制数。

    八进制数字与二进制数字对应关系如下:

    000 -> 0 100 -> 4

    001 -> 1 101 -> 5

    010 -> 2 110 -> 6

    011 -> 3 111 -> 7

    例:将八进制的37.416转换成二进制数:

    3 7 . 4 1 6

    011 111 .100 001 110

    即:(37.416)8 =(11111.10000111)2

    例:将二进制的10110.0011 转换成八进制:

    0 1 0 1 1 0 . 0 0 1 1 0 0

    2 6 . 1 4

    即:(10110.011)2 = (26.14)8

    折叠十六进制与二进制的转换

    二进制数转换成十六进制数:从小数点开始,整数部分向左、小数部分向右,每4位为一组用一位十六进制数的数字表示,不足4位的要用“0”补足4位,就得到一个十六进制数。

    十六进制数转换成二进制数:把每一个十六进制数转换成4位的二进制数,就得到一个二进制数。

    十六进制数字与二进制数字的对应关系如下:

    0000 -> 0 0100 -> 4 1000 -> 8 1100 -> C

    0001 -> 1 0101 -> 5 1001 -> 9 1101 -> D

    0010 -> 2 0110 -> 6 1010 -> A 1110 -> E

    0011 -> 3 0111 -> 7 1011 -> B 1111 -> F

    例:将十六进制数5DF.9 转换成二进制:

    5 D F . 9

    0101 1101 1111 .1001

    即:(5DF.9)16 =(10111011111.1001)2

    例:将二进制数1100001.111 转换成十六进制:

    0110 0001 . 1110

    6 1 . E

    即:(1100001.111)2 =(61.E)16

    折叠编辑本段其他资料

    20世纪被称作第三次科技革命的重要标志之一的计算机的发明与应用,其运算模式正是二进制,同时证明了莱布尼兹的原理是正确的。

    折叠二进制数据的表示法

    二进制数据也是采用位置计数法,其位权是以2为底的幂。例如二进制数据110.11,其权的大小顺序为2^2、2^1、2^0、2^-1、2^-2。对于有n位整数,m位小数的二进制数据用加权系数展开式表示,可写为:

    (a(n-1)a(n-2)…a(-m))2=a(n-1)×2^(n-1)+a(n-2)×2^(n-2)+……+a(1)×2^1+a(0)×2^(0)+a(-1)×2^(-1)+a(-2)×2^(-2)+……+a(-m)×2^(-m)

    二进制数据一般可写为:(a(n-1)a(n-2)…a(1)a(0).a(-1)a(-2)…a(-m))2。

    注意:

    1.式中aj表示第j位的系数,它为0和1中的某一个数。

    2.a(n-1)中的(n-1)为下标,输入法无法打出所以用括号括住,避免混淆。

    3.2^2表示2的平方,以此类推。

    【例1102】将二进制数据111.01写成加权系数的形式。

    解:(111.01)2=(1×2^2)+(1×2^1)+(1×2^0)+(0×2^-1)+(1×2^-2)

    二进制和十六进制,八进制一样,都以二的幂来进位的。

    折叠莱布尼茨与二进制

    在德国图灵根著名的郭塔王宫图书馆(Schlossbiliothke zu Gotha)保存着一份弥足珍贵的手稿,其标题为:“1与0,一切数字的神奇渊源。这是造物的秘密美妙的典范,因为,一切无非都来自上帝。”这是德国天才大师莱布尼茨(Gottfried Wilhelm Leibniz,1646 - 1716)的手迹。但是,关于这个神奇美妙的数字系统,莱布尼茨只有几页异常精炼的描述。

    莱布尼茨不仅发明了二进制,而且赋予了它宗教的内涵。他在写给当时在中国传教的法国耶稣士会牧师布维(Joachim Bouvet,1662 - 1732)的信中说:“第一天的伊始是1,也就是上帝。第二天的伊始是2,……到了第七天,一切都有了。所以,这最后的一天也是最完美的。因为,此时世间的一切都已经被创造出来了。因此它被写作‘7’,也就是‘111’(二进制中的111等于十进制的7),而且不包含0。只有当我们仅仅用0和1来表达这个数字时,才能理解,为什么第七天才最完美,为什么7是神圣的数字。特别值得注意的是它(第七天)的特征(写作二进制的111)与三位一体的关联。”

    布维是一位汉学大师,他对中国的介绍是17、18世纪欧洲学界中国热最重要的原因之一。布维是莱布尼茨的好朋友,一直与他保持着频繁的书信往来。莱布尼茨曾将很多布维的文章翻译成德文,发表刊行。恰恰是布维向莱布尼茨介绍了《周易》和八卦的系统,并说明了《周易》在中国文化中的权威地位。

    八卦是由八个符号组构成的占卜系统,而这些符号分为连续的与间断的横线两种。这两个后来被称为“阴”、“阳”的符号,在莱布尼茨眼中,就是他的二进制的中国翻版。他感到这个来自古老中国文化的符号系统与他的二进制之间的关系实在太明显了,因此断言:二进制乃是具有世界普遍性的、最完美的逻辑语言。

    另一个可能引起莱布尼茨对八卦的兴趣的人是坦泽尔(Wilhelm Ernst Tentzel),他当时是图灵根大公爵硬币珍藏室的领导,也是莱布尼茨的好友之一。在他主管的这个硬币珍藏中有一枚印有八卦符号的硬币。

    与中国易经的联系

    1679年3月15日戈特弗里德·威廉·莱布尼茨发明了一种计算法,用两位数代替原来的十位数,即1 和 0。 1701年他写信给在北京的神父 Grimaldi(中文名字闵明我)和 Bouvet(中文名字白晋)告知自己的新发明,希望能引起他心目中的“算术爱好者”康熙皇帝的兴趣。

    白晋很惊讶,因为他发现这种“二进制的算术”与中国古代的一种建立在两个符号基础上的符号系统是非常近似的,这两个符号分别由一条直线和两条短线组成,即── 和 — —。这是中国最著名大概也是最古老的书《易经》的基本组成部分,据今人推测,该书大约产生于公元前第一个千年的初期,开始主要是一部占卜用书,里边的两个符号可能分别代表“是”和“不”。

    莱布尼茨对这个相似也很吃惊,和他的笔友白晋一样,他也深信《易经》在数学上的意义。他相信古代的中国人已经掌握了二进制并在科学方面远远超过当代的中国人。现在我们可以肯定地说,这种解释与《易经》没有联系。《易经》不是数学书,而是一本“预言”,并在漫长的历史中逐渐演变为一本“智慧之书”。书里的短线意味着阴阳相对,也即天与地、光明与黑暗、造物主和大自然。六爻以不同的组合出现,人们可以借此对自然界和人类生活的变换做出各种不同的解释。比利时神父 P.Couplet(中文名字柏应理)的 Confucius.Sinarum Philosophus (《孔子,中国人的思想家,…》)第一次在欧洲发表了易经的六十四幅六爻八卦图。

    这一次将数学与古代中国《易经》相联的尝试是不符合实际的。莱布尼茨的二进制数学指向的不是古代中国,而是未来。莱布尼茨在1679年3月15日记录下他的二进制体系的同时,还设计了一台可以完成数码计算的机器。我们今天的现代科技将此设想变为现实,这在莱布尼茨的时代是超乎人的想象能力的。

    计算机内部采用二进制的原因

    (1)技术实现简单,计算机是由逻辑电路组成,逻辑电路通常只有两个状态,开关的接通与断开,这两种状态正好可以用“1”和“0”表示。

    (2)简化运算规则:两个二进制数和、积运算组合各有三种,运算规则简单,有利于简化计算机内部结构,提高运算速度。

    (3)适合逻辑运算:逻辑代数是逻辑运算的理论依据,二进制只有两个数码,正好与逻辑代数中的“真”和“假”相吻合。

    (4)易于进行转换,二进制与十进制数易于互相转换。

    (5)用二进制表示数据具有抗干扰能力强,可靠性高等优点。因为每位数据只有高低两个状态,当受到一定程度的干扰时,仍能可靠地分辨出它是高还是低。

    折叠二进制与周易的澄清

    改革开放前,大多数中国人不知道计算机是什么东西。1980年,美国人第一台8086CPU芯片个人计算机(PC,俗称电脑)上市,80年代初,中国出现了进口电脑。一台苹果机,价格近两万元,是普通干部工人工资的数百倍,个人根本没有能力购买。90年代以后中国有了互联网,电脑才逐步为中国人所熟悉。

    面对外来的先进科学技术,中国有些传统文化人很不服气,连基本数学常识都没有,却说什么计算机二进制原理,源于中国的《周易》。这些文化人有个共同特点,大力宣扬用传统文化抵制西方文化的同时,却喜欢拉个外国名人为自己壮胆。可是忽略了一点,老祖宗的东西既然如此伟大,为什么中国人发明不了,愣是让西方人莱布尼兹抢了头功?

    飞机与鸟儿都能在高空中飞翔,飞机的原理却不是来自鸟类。同样,莱布尼兹见过中国的太极图,不能证明计算机二进制原理源于《易经》。

    据说伏羲创八卦。传说中的伏羲时代已有5000多年历史了。5000多年前的人类已经有了计数能力,可是还没有“0”这个数字概念,直到公元628年,印度人Brahmagupta首次使用O。12世纪印度人Bhaskara指出正数的平方根有两个,一正一负。(《数学:确定性的丧失 英.M.克来因》湖南科技出版社)。

    0不仅仅表示“无”或“没有”,如气温0度,不是没有温度。有了0,就可建立一个参照系,如在一条直线上任取一点为0,0点的左边为负数,右边为正数。

    学过计算机原理的人都知道,计算机电路的高电平和低电平对应二进制数1与0。若高电平为1,则低电平为0;反之,高电平为0,低电平为1。这是正逻辑与反逻辑问题。计算机的工作原理基于“布尔代数”,进行逻辑运算。计算机电路尽管十分复杂,但基本单元却很简单,由或门、与门、非门、与非门、或非门、异或门、同或门等组成。

    因为计算机是高科技,有人就想当然,二进制也是高科技。如百家讲坛的毛佩奇教授在他的《图解周易》书中说,二进制是“世界上数学进制中最先进的”,“20世纪被称作第三次科技革命的重要标志之一的计算机的发明与应用,其运算模式是二进制。它不但证明了莱布尼茨的原理是正确的,同时也证明了《易经》数理原理是很了不起的。”

    毛教授代表了相当一部分中国传统文化人的观点。这是对数学进制的无知,数学的进制原理,不存在“正确”与“错误”,更没有“先进”与“落后”之分。

    用什么制式进行数学运算,要看什么场合,什么方便用什么。数学上有二进制、八进制、十进制、十六进制、六十进制,…等多种进制,原则上可取任何数进制,只要它实用。12个月一年是十二进制,365天一年是三百六十五进制。不同进制的数可以相互转换,如十进制135,转换成二进制为10000111,二进制的101转换成十进制为5。很显然,若人工进行十进制计算135除5,十分简捷,但换成二进制100001111除101,计算起来既费力又费时间,是最笨拙的进制。

    易经八卦阳爻为一长划“一”,阴爻为一断划“--”(马王堆西汉考古证明,阴爻为“<”。后来演变成“--”),阴阳二爻任取三爻成一卦,共八个卦,八卦两两叠加,成六十四卦。这是十进制数的乘方运算,23=8,82=64,与二进制毫不相关。

    有人认为,把八卦的阳爻“一”视作1,阴爻“--”视作0,就是二进制。这是牵强附会,因为八卦产生的年代还没有0与1的概念。

    乾坤二卦象征天地。乾卦由三个阳爻“一”上下叠加组成,坤卦由三个阴爻“--”上下叠加组成。若把阳爻符号“一”看成1,阴爻符号“--”视作0,则乾卦三个爻为二进制111,对应十进制7;坤卦三个爻为二进制000,对应十进制0。

    《系辞》曰:“易有太极,是生两仪,两仪生四象,四象生八卦”,太极即无,无中生有,产生8个卦。若0等于无,太极即0,这岂不与上面说的坤为0相矛盾?并且,乾一、兑二、离三、震四、巽五、坎六、艮七、坤八,八个卦的“数”,都不能与各自六个爻符转换成的“二进制数”一一对应。

    两个八卦叠加成六十四卦,六十四卦各由六个爻组成。如乾卦为六个“一”,对应二进制111111,转换成十进制,25+24+23+22+21+20=63;坤卦六个阴爻“--”,对应二进制000000,转换成十进制仍为0。六十四个卦的“数”,与各自的六个爻符转换成的“二进制数”,也不能一一对应。

    古代汉字有“零”,零并不等于0,零的含意是:1,部分的、细碎的,与整相对,如零碎、十元零八毛;2,落,如雕零。零的现代意义,可以是无,如“一切从零开始”。

    没有0这个数,二进制无从谈起(有没有0不重要,0和1只是代表了开和关二字。)。

    《易经》有数理原理,八八六十四卦有简单的算术运算,但二进制源于八卦之说,是以讹传讹。远古时代先民画的八卦占卜符号,竞成了高科技计算机的数学原理,无疑是现代版的天方夜谭。

    处理数据库二进制数据

    我们在使用数据库时,有时会用到图像或其它一些二进制数据,这个时候你们就必须使用getchunk这个方法来从表中获得二进制大对象,我们也可以使用AppendChunk来把数据插入到表中.

    我们平时来取数据是这样用的!

    Getdata=rs("fieldname")

    而取二进制就得这样

    size=rs("fieldname").acturalsize

    getdata=rs("fieldname").getchunk(size)

    我们从上面看到,我们取二进制数据必须先得到它的大小,然后再搞定它,这个好像是ASP中处理二进制数据的常用方法,我们在获取从客户端传来的所有数据时,也是用的这种方法。

    下面我们也来看看是怎样将二进制数据加入数据库

    rs("fieldname").appendchunk binarydata

    一步搞定!

    另外,使用getchunk和appendchunk将数据一步一步的取出来!

    下面演示一个取数据的例子!

    Addsize=2

    totalsize=rs("fieldname").acturalsize

    offsize=0

    Do Where offsize Binarydata=rs("fieldname").getchunk(offsize)

    data=data&Binarydata

    offsize=offsize+addsize

    Loop

    当这个程序运行完毕时,data就是我们取出的数据.    

    数学名词
    八边形 八面体 百分比 百分点 百分位数
    半径 半球 半圆 被乘数 被除数
    被加数 被减数 比例
    变量 标准差 表面积 并集 补集
    不等边三角形 不等式 不定积分
    常量 乘方 乘数
    除数 垂心 次方 次方根 大于
    大于等于 代数 单调性 单项式 导数
    等边三角形 等式方程式 等腰三角形 等腰梯形 等于
    底面 定积分 定理
    定义域 对数 钝角 钝角三角形 多边形
    多面体 二次方程 多项式 二次方根平方根 二次方平方
    二进制 二十面体 反余割 反余切 反余弦
    反正割 反正切 反正弦 方差 非正态分布
    分布 分母 分数 分子
    复数
    公理 公式 勾股定理 轨迹
    函数 横坐标 弧度
    积分 极限 集合
    几何 计算 加权平均数 加数
    假设 减数 交集
    角度 阶乘 截尾 进位 九边形
    九面体 矩形 矩阵 开方 空集
    空间 棱台 棱柱 棱锥
    立方体 菱形 六边形 六面体
    面积 命题 内切圆 内心
    排列 旁心 抛物线 平角 平均数
    平行 平行六面体 平行四边形 七边形 七面体
    奇偶性 曲线统计图 全等
    锐角 锐角三角形
    三次方程 三次方根立方根 三次方立方 三角 三角形
    扇形 扇形统计图 上舍入 射线
    十边形 十二边形 十二面体 十进制 十六进制
    十面体 十一边形 十一面体 实数
    数列级数 数字 双曲线 四边形 四次方
    四次方程 四次方根 四面体 四舍五入 算术
    梯形 体积 条形统计图 统计
    图表 图象 椭圆 外切圆 外心
    微分 微积分 未知数 无理数 无穷大
    无穷小 无效数字 五边形 五面体 系数
    下舍入 线 线段 相交 相似
    相位 小数 小数点 小于 小于等于
    斜边 行列式 虚数 旋转 一次方程
    映射 有理数 有效数字 余割 余切
    余弦 元素 原点 圆台
    圆心 圆周 圆周率 圆柱 圆锥
    运算 运算符 折线统计图 振幅 整数
    正多边形 正方形 正割 正切
    正态分布 正弦 证明 直角 直角边
    直角三角形 直角梯形 直径 值域 指数幂
    重心 周长 周角 周期 周期性
    柱形统计图 子集 自然数 纵坐标
    组合 坐标系 坐标轴

     

    转载于:https://www.cnblogs.com/jmsjh/p/7281992.html

    展开全文
  • 简单的二进制

    2016-07-07 21:29:12
    基本常识点 莱布尼茨“逢二进一”、“ 借一当二”机器语言开关高低位 进制转换 正整数转二进制小数转二进制负整数转二进制二进制 八进制二进制 十六进制

    基本常识点

    • 莱布尼茨
    • “逢二进一”、“ 借一当二”
    • 机器语言
    • 开关
    • 高低位

    进制转换

    正整数转二进制


    小数转二进制


    负整数转二进制


    二进制 八进制


    二进制 十六进制


    位运算符

    & 按位与

    清零

    若想对一个存储单元清零,即使其全部二进制位为0,只要找一个二进制数,其中各个位符合一下条件:

    原来的数中为1的位,新数中相应位为0。然后使二者进行&运算,即可达到清零目的。

    a 00101011

    b 10010100

    c 00000000 //c = a & b

    取一个数中某些指定位

    若有一个整数a(2byte),想要取其中的低字节,只需要将a与8个1按位与即可。

    a 00101100 10101100

    b 00000000 11111111

    c 00000000 10101100 //c = a & b

    保留指定位

    a 01010100

    b 00111011

    c 00010000 //c = a & b

    | 按位或

    两个相应的二进制位中只要有一个为1,该位的结果值为1。借用逻辑学中或运算的话来说就是,一真为真
    应用:将一个数据的某些位定值为1
    a 00110000
    b 00001111

    c 00111111 //c = a | b

    ^ 按位异或

    ~ 取反

    << 左移

    n位意味着乘以2^n

    >> 右移

    n位意味着除以2^n

    原码 反码 补码

    原码 

    原码就是符号位加上真值的绝对值, 即用第一位表示符号, 其余位表示值.

    比如如果是8位二进制:

    [+1]原 = 0000 0001

    [-1]原 = 1000 0001

    第一位是符号位. 因为第一位是符号位, 所以8位二进制数的取值范围就是:

    [1111 1111 , 0111 1111] 即 [-127 , 127]

    原码是人脑最容易理解和计算的表示方式。

    反码

    反码的表示方法是:

    正数的反码是其本身

    负数的反码是在其原码的基础上, 符号位不变,其余各个位取反.

    [+1] = [00000001]原 = [00000001]反

    [-1] = [10000001]原 = [11111110]反

    可见如果一个反码表示的是负数, 人脑无法直观的看出来它的数值. 通常要将其转换成原码再计算.

    补码

    补码的表示方法是:

    正数的补码就是其本身

    负数的补码是在其原码的基础上, 符号位不变, 其余各位取反, 最后+1. (即在反码的基础上+1)

    [+1] = [00000001]原 = [00000001]反 = [00000001]补

    [-1] = [10000001]原 = [11111110]反 = [11111111]补

    对于负数, 补码表示方式也是人脑无法直观看出其数值的. 通常也需要转换成原码在计算其数值.

    补码举例:16位的变量求补码,比如-266的补码求法:( ( 266 ^ 0xffff ) + 1 ) 结果是0xfef6

    二进制思想

    假设有1000个苹果,现在要取n个苹果,如何取?正常的做法应该是将苹果一个一个拿出来,直到n个苹果被取出来。

      又假设有1000个苹果和10只箱子,如何快速的取出n个苹果呢?可以在每个箱子中放 2^i (i<=0<=n)个苹果,也就是 1、2、4、8、16、32、64、128、256、489(最后的余数),相当于把十进制的数用二进制来表示,取任意n个苹果时,只要推出几只箱子就可以了。

    二进制实例

    任意给定一个32位无符号整数n,求n的二进制表示中1的个数,比如n = 5(0101)时,返回2,n = 15(1111)时,返回4

    普通法:

    int BitCount(unsigned int n)
    {
        unsigned int c =0 ; // 计数器
        while (n >0)
        {
            if((n &1) ==1) // 当前位是1
                ++c ; // 计数器加1
            n >>=1 ; // 移位
        }
        return c ;
    }
    …………………………………………

    int BitCount1(unsigned int n)
    {
        unsigned int c =0 ; // 计数器
        for (c =0; n; n >>=1) // 循环移位
            c += n &1 ; // 如果当前位是1,则计数器加1
        return c ;
    }

    快速法:

    int BitCount2(unsigned int n)
    {
        unsigned int c =0 ;
        for (c =0; n; ++c)
        {
            n &= (n -1) ; // 清除最低位的1
        }
        return c ;
    }

    展开全文
  • 计算机二进制储存

    千次阅读 2018-10-09 01:26:37
    计算机二进制储存 我们都知道,计算机储存数据最终都是转换成二进制数字进行储存,而计算机进行简单的运算时,也是通过二进制下的数字进行计算的,下面我们就探究一下计算机在二进制储存下的计算方式。 首先我们在...
  • 自己的需求:有四个变量,寻求最优化的结果。 跟那些用二元函数举例的不同。 首先介绍下, 1. 遗传算法的流程: 假设有100个个体,计算每个个体的适应度(即性能),通过轮盘算法,选择100个个体,这100个不是...
  • 浮点数二进制表示

    千次阅读 2014-10-10 19:23:15
    上面这条命令,声明了一个整数变量,类型为int,值为9(二进制写法为1001)。普通的32位计算机,用4个字节表示int变量,所以9就被保存为00000000 00000000 00000000 00001001,写成16进制就是0x00000009。 那么,...
  • MySQL二进制日志

    2018-11-02 12:57:38
    简介 二进制日志包含数据库的所有更改的记录,包括数据和结构,以及每个语句执行的时间。它由一组二进制日志文件和索引组成。...二进制日志以二进制文本格式存储,因此无法使用常规编辑器查看。需要用mysq...
  • 二进制基础

    2019-06-29 13:52:33
    阅读源码时,会出现很多关于二进制基础和位运算的东西,再次进行一个巩固和记录。 如果想详细了解的,可以去看这个链接下的视频,讲的非常棒。https://www.imooc.com/video/3649 1.二进制的概念 1.1 二进制与十进制...
  • 二进制转十进制计算器二进制:十进制:进制:进制:转换说明:上面第一行可将二进制转换为十进制,第二行可以将任意进制转换为任意进制。64个基数为:"[emailprotected]"注意:本工具只是各种进制计数法的数之间的...
  • MATLAB读二进制文件

    2020-01-06 21:14:18
    fopen : 打开文件,以二进制形式访问,并返回大于或等于3的整数,作为文件标识符。(MATLAB® 保留文件标识符 0、1 和 2 分别用于标准输入、标准输出(屏幕)和标准错误。)如果fopen无法打开文件,则返回-1. ...
  • 浮点数的二进制表示

    2016-10-12 15:13:05
    浮点数的二进制表示
  • 不过,由于数据在计算机中的表示,最终以二进制的形式存在,所以有时候使用二进制,可以更直观地解决问题。但,二进制数太长了。比如int 类型占用4个字节,32位。比如100,用int类型的二进制数表达将是:0000 0000 ...
  • 举例验证十进制转二进制,十进制转换十六进制: 代码演示: #include <stdio.h> #include <stdlib.h> #include <string.h> void trans(char array[],int number,int scale,int * len) { int i ...
  • 通常我们交换两个变量都会用一个中间值来存储然后交换,用int来举例: int a = 1, b = 2; int temp;//中间值 temp=a,a=b,b=temp; 这样就很简单,我们也可以用差值法 int a = 1, b = 2; a=a+b; b=a-b; a=a-b; ...
  • Threejs 拓展之二进制数组

    千次阅读 2017-12-12 16:43:47
    在Threejs 的学习过程中,分配缓存区域时需要调用JavaScript中的Uint16Array、Float32Array等对象来分配连续的内存空间。...二进制数组 详细的介绍了上面的几个对象。 二进制数组 二进制数组(ArrayBuffer
  • 二进制加,减法,23个位运算技巧

    千次阅读 2019-04-06 20:36:22
    二进制加,减法 二进制最高位为1时表示负数,为0时表示正数。 **原码:**一个正数,转换为二进制位就是这个正数的原码。负数的绝对值转换成二进制位然后在高位补1就是这个负数的原码。 举例说明:  int类型的 3 的...
  • C++对二进制文件的读写操作

    千次阅读 2018-06-14 20:59:51
    因为项目需要,所以需要学习一下对二进制文件读写的操作,特此记录成长也跟大家总结分享一下较为全面的用法! 百度经验 二进制文件不是以ASCII形式存放数据的,它将内存中数据存储形式不加转换地传送到磁盘文件,...
  • 文本文件和二进制文件学习

    千次阅读 2016-07-03 20:23:46
     二进制文件与我们通常使用的文本文件储存方式有根本的不同。这样的不同很难用言语表达,自己亲自看一看,理解起来会容易得多。因此,我推荐学习二进制文件读写的朋友安装一款十六进制编辑器。这样的编辑器有很多,...
  • 二进制、八进制、十六进制 6.1 为什么需要八进制和十六进制? 6.2 二、八、十六进制数转换到十进制数  6.2.1 二进制数转换为十进制数  6.2.2 八进制数转换为十进制数  6.2.3 八进制数的表达方法 ...
  • 二进制文件读取——转载

    千次阅读 2018-10-09 11:06:50
    C++学习49 对二进制文件的读写操作 转载:https://www.cnblogs.com/Caden-liu8888/p/5843994.html 二进制文件不是以ASCII代码存放数据的,它将内存中数据存储形式不加转换地传送到磁盘文件,因此它又称为内存数据的...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 62,361
精华内容 24,944
关键字:

二进制变量举例