TypeScript-Int64实现

TypeScript-Int64实现TypeScript Int64 实现查了一些实现资料 找到以下几个 Int64 解决方案 整理起来 最后一个需要翻墙 直接把代码贴上 可以参考一下 一 Javascript 的 64bitInt 支持 2 个 uint 拼接这酸爽 packagelz jprotoc importflash utils IDataInput authorliz

TypeScript-Int64实现

查了一些实现资料,找到以下几个Int64解决方案,整理起来。最后一个需要翻墙,直接把代码贴上,可以参考一下。

一、Javascript 的 64bit Int 支持

2个uint 拼接

这酸爽……

package lz.jprotoc { 
    import flash.utils.IDataInput; / * ... * @author lizhi http://matrix3d.github.io/ */ public class Int64 { 
    public var low:uint = 0; public var high:uint = 0; public function Int64(low:uint=0,high:uint=0) { 
    this.low = low; this.high = high; } public function equal(v:Int64):Boolean { 
    if (v == null) return false; return (v.low == low) && (v.high == high); } public function isZero():Boolean { 
    return low == 0 && high == 0; } public function toString():String { 
    return "high:0x" + high.toString(16)+" low:0x" + low.toString(16); } } } 

虽然是 AS3 写的,但转成 JS 也是分分钟。

字符串拼接法

dom 同学用 ByteArray 来保存每个字节 (同样是 AS3),然后将其转成字符串来显示,缺点和上面 lizi 的一样,就是无法计算。

node-int64

node-int64 采用 Javascript 的 Number 来实现对超过 int32 的数值的保存。由于 Number 采用 双精度浮点数 来保存数值,因此该值的范围只能在 +/- 253 的范围内。

这是我最终的选择。因为金币的值在客户端是会参与计算的,但估计在游戏的有生之年都不可能大于 253 。

我基于该版本修改了一个 TypeScript 版的 Int64.ts,可以在 egret 中使用。

Number.isSafeInteger

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/isSafeInteger

TishoYs Space 提到了使用 Number.isSafeInteger + parseInt 来处理 Int64,需要注意几个问题:

Number.isSafeInteger = Number.isSafeInteger || function (value) { 
    return Number.isInteger(value) && Math.abs(value) <= Number.MAX_SAFE_INTEGER; }; 

二、Int64.ts and Buffer.ts for Egret

前几天写了一篇 Javascript 的 64bit Int 支持,列举了一些在 Javascript 中支持 64bit 数值的已有方法。

其实,写那篇是为了在 egret 中支持 64bit 数值,原因么,上一篇有讲。

由于 egret 使用的是 TypeScript ,我基于 node-int64 翻译了一个 TypeScript 版本Int64.ts ,方便伸手党。同时为了方便和服务端大爷通信,又继承 egert.ByteArray 写了个 Buffer.ts 。

note-int64 采用的是 node 的 Buffer 来保存 64bit 数字信息。我给改成了使用 egret.ByteArray 。后来为了更加通用,又改成了直接使用 Array。

Buffer.ts 中则仅仅实现了 readInt64 和 writeInt64,Unsigned 版本直接调用这两个方法。

这两个文件都在 gist 上,请科学上网。

给一段测试代码:

 var i64:Int64 = new Int64(0x07); var buf:Buffer = new Buffer(); buf.writeInt64(i64); buf.writeUnsignedInt64(i64.toNumber()); buf.position = 0; for(var i:number=0;i<buf.length;i++) { 
     console.log(buf.readByte()); } buf.position = 0; console.log(buf.readInt64()); console.log(buf.readUnsignedInt64()); // 1 // 2 // 3 // 4 // 5 // 6 // 7 // 0 // 1 // 2 // 3 // 4 // 5 // 6 // 7 // 6183 // 6183 

三、完整方案 链接需要科学上网。。

https://gist.github.com/zrong/6e8d6bb0539bf2#file-int64-ts

Buffer.ts

 // Buffer.ts // extend egret.ByteArray, implement writeInt64 // @author  // Creation 2015-09-14  class Buffer extends egret.ByteArray { 
     private static SIZE_OF_INT64:number = 8; private static SIZE_OF_UINT64:number = 8; constructor(buffer?:ArrayBuffer) { 
     super(buffer); } public readUnsignedInt64(raw=true):any { 
     return this.readInt64(raw); } public writeUnsignedInt64(value:any):void { 
     this.writeInt64(value); } public readInt64(raw=true):any { 
     if (!this.validate(Buffer.SIZE_OF_INT64)) return null; var buffer:Array<number> = []; for(var i:number=0; i<Buffer.SIZE_OF_INT64; i++) { 
     buffer[i] = this.readByte(); } var intValue:Int64 = new Int64(buffer); if(raw) { 
     return intValue.toNumber(); } return intValue; } public writeInt64(value:any):void { 
     var intValue:Int64; if(typeof(value) == 'number') { 
     intValue = new Int64(value); } else { 
     intValue = value; } var buffer:Array<number> = intValue.toBuffer(true); for(var i:number=0; i<buffer.length; i++) { 
     this.writeByte(buffer[i]); } } } 

Int64.js

// Int64.js // // Copyright (c) 2012 Robert Kieffer // MIT License - http://opensource.org/licenses/mit-license.php / * Support for handling 64-bit int numbers in Javascript (node.js) * * JS Numbers are IEEE-754 binary double-precision floats, which limits the * range of values that can be represented with integer precision to: * * 2^^53 <= N <= 2^53 * * Int64 objects wrap a node Buffer that holds the 8-bytes of int64 data. These * objects operate directly on the buffer which means that if they are created * using an existing buffer then setting the value will modify the Buffer, and * vice-versa. * * Internal Representation * * The internal buffer format is Big Endian. I.e. the most-significant byte is * at buffer[0], the least-significant at buffer[7]. For the purposes of * converting to/from JS native numbers, the value is assumed to be a signed * integer stored in 2's complement form. * * For details about IEEE-754 see: * http://en.wikipedia.org/wiki/Double_precision_floating-point_format */ // // Int64 // class Int64 { 
     // Useful masks and values for bit twiddling public static MASK31:number = 0x7fffffff; public static VAL31:number = 0x; public static MASK32:number = 0xffffffff; public static VAL32:number = 0x; public static MAX_INT:number = Math.pow(2, 53); public static MIN_INT:number = -Math.pow(2, 53); private static _HEX:Array<any> = new Array<any>(); public buffer:Array<number>; public offset:number; / * Constructor accepts any of the following argument types: * * new Int64(buffer[, offset=0]) - Existing Buffer with byte offset * new Int64(Uint8Array[, offset=0]) - Existing Uint8Array with a byte offset * new Int64(string) - Hex string (throws if n is outside int64 range) * new Int64(number) - Number (throws if n is outside int64 range) * new Int64(hi, lo) - Raw bits as two 32-bit values */ public constructor(a1:any, a2?:any) { 
     this._buildHex(); if (a1 instanceof Array) { 
     this.buffer = a1; this.offset = a2 || 0; } else if (Object.prototype.toString.call(a1) == '[object Uint8Array]') { 
     // Under Browserify, Buffers can extend Uint8Arrays rather than an // instance of Buffer. We could assume the passed in Uint8Array is actually // a buffer but that won't handle the case where a raw Uint8Array is passed // in. We construct a new Buffer just in case. this.buffer = Array.apply([], a1); this.offset = a2 || 0; } else { 
     this.buffer = this.buffer || []; this.offset = 0; this.setValue.apply(this, arguments); } } // Map for converting hex octets to strings private _buildHex():void { 
     //Int64._HEX = []; for (var i = 0; i < 256; i++) { 
     Int64._HEX[i] = (i > 0xF ? '' : '0') + i.toString(16); } } / * Do in-place 2's compliment. See * http://en.wikipedia.org/wiki/Two's_complement */ private _2scomp() { 
     var b = this.buffer, o = this.offset, carry = 1; for (var i = o + 7; i >= o; i--) { 
     var v = (b[i] ^ 0xff) + carry; b[i] = v & 0xff; carry = v >> 8; } } / * Set the value. Takes any of the following arguments: * * setValue(string) - A hexidecimal string * setValue(number) - Number (throws if n is outside int64 range) * setValue(hi, lo) - Raw bits as two 32-bit values */ public setValue(hi:any, lo?:any):void { 
     var negate:boolean = false; if (arguments.length == 1) { 
     if (typeof(hi) == 'number') { 
     // Simplify bitfield retrieval by using abs() value. We restore sign // later negate = hi < 0; hi = Math.abs(hi); lo = hi % Int64.VAL32; hi = hi / Int64.VAL32; if (hi > Int64.VAL32) throw new RangeError(hi + ' is outside Int64 range'); hi = hi | 0; } else if (typeof(hi) == 'string') { 
     hi = (hi + '').replace(/^0x/, ''); lo = hi.substr(-8); hi = hi.length > 8 ? hi.substr(0, hi.length - 8) : ''; hi = parseInt(hi, 16); lo = parseInt(lo, 16); } else { 
     throw new Error(hi + ' must be a Number or String'); } } // Technically we should throw if hi or lo is outside int32 range here, but // it's not worth the effort. Anything past the 32'nd bit is ignored. // Copy bytes to buffer var b = this.buffer, o = this.offset; for (var i = 7; i >= 0; i--) { 
     b[o+i] = lo & 0xff; lo = i == 4 ? hi : lo >>> 8; } // Restore sign of passed argument if (negate) this._2scomp(); } / * Convert to a native JS number. * * WARNING: Do not expect this value to be accurate to integer precision for * large (positive or negative) numbers! * * @param allowImprecise If true, no check is performed to verify the * returned value is accurate to integer precision. If false, imprecise * numbers (very large positive or negative numbers) will be forced to +/- * Infinity. */ public toNumber(allowImprecise:boolean=false):number { 
     var b = this.buffer, o = this.offset; // Running sum of octets, doing a 2's complement var negate = b[o] & 0x80, x = 0, carry = 1; for (var i = 7, m = 1; i >= 0; i--, m *= 256) { 
     var v = b[o+i]; // 2's complement for negative numbers if (negate) { 
     v = (v ^ 0xff) + carry; carry = v >> 8; v = v & 0xff; } x += v * m; } // Return Infinity if we've lost integer precision if (!allowImprecise && x >= Int64.MAX_INT) { 
     return negate ? -Infinity : Infinity; } return negate ? -x : x; } / * Convert to a JS Number. Returns +/-Infinity for values that can't be * represented to integer precision. */ public valueOf():number { 
     return this.toNumber(false); } / * Return string value * * @param radix Just like Number#toString()'s radix */ public toString(radix:number=10):string { 
     return this.valueOf().toString(radix); } / * Return a string showing the buffer octets, with MSB on the left. * * @param sep separator string. default is '' (empty string) */ public toOctetString(sep:string=''):string { 
     var out = new Array(8); var b = this.buffer, o = this.offset; for (var i = 0; i < 8; i++) { 
     out[i] = Int64._HEX[b[o+i]]; } return out.join(sep || ''); } / * Returns the int64's 8 bytes in a buffer. * * @param {bool} [rawBuffer=false] If no offset and this is true, return the internal buffer. Should only be used if * you're discarding the Int64 afterwards, as it breaks encapsulation. */ public toBuffer(rawBuffer:boolean=false):Array<number> { 
     if (rawBuffer && this.offset === 0) return this.buffer; var out = Array.call([], this.buffer); return out; } / * Returns a number indicating whether this comes before or after or is the * same as the other in sort order. * * @param {Int64} other Other Int64 to compare. */ public compare(other:Int64):number { 
     // If sign bits differ ... if ((this.buffer[this.offset] & 0x80) != (other.buffer[other.offset] & 0x80)) { 
     return other.buffer[other.offset] - this.buffer[this.offset]; } // otherwise, compare bytes lexicographically for (var i = 0; i < 8; i++) { 
     if (this.buffer[this.offset+i] !== other.buffer[other.offset+i]) { 
     return this.buffer[this.offset+i] - other.buffer[other.offset+i]; } } return 0; } / * Returns a boolean indicating if this integer is equal to other. * * @param {Int64} other Other Int64 to compare. */ public equals(other:Int64):boolean { 
     return this.compare(other) === 0; } / * Pretty output in console.log */ public inspect():string { 
     return '[Int64 value:' + this + ' octets:' + this.toOctetString(' ') + ']'; } } 

参考

  • https://blog.zengrong.net/post/2363.html
  • https://blog.zengrong.net/post/2367.html
  • https://gist.github.com/zrong/6e8d6bb0539bf2#file-int64-ts 感谢作者!
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/216007.html原文链接:https://javaforall.net

(0)
上一篇 2026年3月18日 下午12:47
下一篇 2026年3月18日 下午12:47


相关推荐

  • fileinput基本使用[通俗易懂]

    fileinput基本使用[通俗易懂]新增$(“#attachmentsFile”).fileinput({theme:”fa”,showPreview:true,//是否显示预览hideThumbnailContent:true,//是否在缩略图中隐藏预览内容(图像,pdf内容,文本内容等)。showUpload:false,//隐藏上传按钮…

    2022年6月7日
    40
  • 两大升级要点!Midjourney-v7版本强在哪里?

    两大升级要点!Midjourney-v7版本强在哪里?

    2026年3月15日
    6
  • Linux 5nd Day

    Linux 5nd Day

    2021年8月7日
    55
  • RAG知识库+AI工作流+Agent:Dify对比ChatWiki对比MaxKB 等 LLM框架怎么选(附教程)

    RAG知识库+AI工作流+Agent:Dify对比ChatWiki对比MaxKB 等 LLM框架怎么选(附教程)

    2026年3月12日
    3
  • pycharm debug|新手入门

    pycharm debug|新手入门文章目录前言一 debug 常识二 debug 时遇到的问题及解决办法三 程序中遇到某些特殊情况应该如何 debug 前言分条整理 debug 时的注意事项 debug 时遇到的问题及解决办法 程序中遇到某些特殊情况应该如何 debug 以下是本篇文章正文内容 一 debug 常识 1 设置断点是 debug 的第一步 设置断点多在主程序代码行中设置 2 设置好断点 debug 运行 然后 F8 单步调试 遇到想进入的函数 F7 进去 想出来在 shift F8 跳过不想看的地方 直接设置下一个断点 然后 F9 直

    2026年3月27日
    2
  • myccl初次使用(zz)

    myccl初次使用(zz)修改特征代码免杀一般分为文件和内存二种 我们要先查找文件特征码进行免杀 表面免杀 然后才可以查找内存特征代码进行免杀 给木马加壳 加花 加密 这样文件 表面 免杀了 不等于文件特征码免杀 操作步骤 首先我们要生成一个无壳的木马客户端 我已经生成好了 打开 MYCCL 复合特征码定位器软件 把我们要查找的木马打开 目录 大家可以随便建一个 分块个数设置在 50 100 之间 单位长度和填

    2026年3月17日
    2

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号