powerbuilder Decimal内部表示方式解析

Decimal是16bytes数据类型。最大精度18位。

如果申明时写:dec var1 = xxx,它内部初始值会自动设置精度:

000014d9h: 01 00 08 00 F6 FF 09 00 00 00 00 00 00 00 B8 00 dec{8} q111111111111111111 = -0.0065535
000014d9h: 01 00 0C 00 60 79 9E 86 01 00 00 00 00 00 B8 00 dec{12} q111111111111111111 = -0.0065535
000014c9h: 01 00 00 00 FF FF 00 00 00 00 00 00 00 00 B8 00 dec q111111111111111111 = -65535
000014d9h: 01 00 01 00 FF FF 00 00 00 00 00 00 00 00 B8 00 dec q111111111111111111 = -6553.5
000014d9h: 01 00 02 00 FF FF 00 00 00 00 00 00 00 00 B8 00 dec q111111111111111111 = -655.35
000014d9h: 01 00 03 00 FF FF 00 00 00 00 00 00 00 00 B8 00 dec q111111111111111111 = -65.535
000014d9h: 01 00 04 00 FF FF 00 00 00 00 00 00 00 00 B8 00 dec q111111111111111111 = -6.5535
000014d9h: 01 00 05 00 FF FF 00 00 00 00 00 00 00 00 B8 00 dec q111111111111111111 = -0.65535
000014d9h: 01 00 06 00 FF FF 00 00 00 00 00 00 00 00 B8 00 dec q111111111111111111 = -0.065535
000014d9h: 01 00 07 00 FF FF 00 00 00 00 00 00 00 00 B8 00 dec q111111111111111111 = -0.0065535
000014d9h: 01 00 08 00 FF FF 00 00 00 00 00 00 00 00 B8 00 dec q111111111111111111 = -0.00065535

由上的hex可见,dec申明时系统决定精度,最大可能满足最好的保存方式。

而dec{8}的方式如果赋值长度超过,将被截取掉。

pbkiller有2个bug,一是没处理正负号,二是小于1的小数,它一直是保持小数点不动,也就是没处理指数(仅仅小于1的情况下,大于1的情况有处理ok)。

内部的二进制表示上看,低2位表示正负号,目前只使用了1bit,3-4位表示精度。4-12是以一个__int64表示的极大整数

为了解析这个decimal格式,整整花了一天时间。pb的real对应c++的float,double对应c++的double。

iGetLen = 8;
longlongValue=0;
memcpy(&longlongValue,pDataResLocal + iDataOrPoint + 4,iGetLen);
sReturn = IntToStr(longlongValue);

//指数部分;如果申明dec var1,这个精度是根据赋值时自动进行的。
//原则是尽可能保存完整。但是如果申明dec{8} var1,这精度是固定的。
//给小数点
inttemp = sReturn.Length(); //长度不要变动,后面给指数时还用到。
if (inttemp >1){
sReturn = sReturn.SubString(1,1) + "." +
sReturn.SubString(2,inttemp - 1);
}

//去掉尾部的多余0
intValue = inttemp + 1; //小数点;
while(intValue>3){
if(sReturn.SubString(intValue,1) == "0"){
intValue --;
if(intValue < 4) break;
}else{
break;
}
}
sReturn = sReturn.SubString(1,intValue);

//变更指数
iGetLen = 2;
intValue = 0;
memcpy(&intValue,pDataResLocal + iDataOrPoint + 2,iGetLen);
if (intValue - inttemp + 1 !=0){
sReturn +="E" + IntToStr(-(intValue - inttemp + 1));
}

//处理正负号
iGetLen = 1;
intValue = 0;
memcpy(&intValue,pDataResLocal + iDataOrPoint,iGetLen);

if(intValue){
sReturn = "-" + sReturn;
}

break;

程序demo:

//
dec{8} q1 = -123.44320123
dec{8} q11 = 0.01
dec{8} q12 = 0.001
dec{8} q13 = 0.0001
dec{8} q14 = 0.00001
dec{8} q15 = 0.000001

dec{8} q16 = 3.14E-5
dec{8} q17 = 6500000000

dec{0} q2= 3.1415926514159265141592651415926514159265 //仅供测试系统的截取情况

dec{4} q3= 3.1415926514159265141592651415926514159265
dec{8} q4= 3.1415926514159265141592651415926514159265
dec{12} q5= 3.1415926514159265141592651415926514159265
dec{16} q6= 3.1415926514159265141592651415926514159265

dec{18} q7= 3.1415926514159265141592651415926514159265

any r1 = 3.1415926514159265141592651415926514159265

pbkiller结果:

decimal q1 = 123.44320123
decimal q11 = .1000000 //here error
decimal q12 = .100000//here error
decimal q13 = .10000 //here error
decimal q14 = .1000 //here error
decimal q15 = .100 //here error
decimal q16 = .3140//here error
decimal q17 = 6500000000.00000000
decimal q2 = 3
decimal q3 = 3.1416
decimal q4 = 3.14159265
decimal q5 = 3.141592651416
decimal q6 = 3.1415926514159265
decimal q7 = 3.141592651415926514
decimal r1 = 3.141592651415926514

我的decomplier:

global <FUNCTION_OR_SUBRUNTINE> <RETURN_DATATYPE> lf_111(<PARAM_LIST>) <THROWS_OBJNAME>
//Variables List
dec{8}q1 = -1.2344320123E2
dec{8}q11 = 1.0E-2
dec{8}q12 = 1.0E-3
dec{8}q13 = 1.0E-4
dec{8}q14 = 1.0E-5
dec{8}q15 = 1.0E-6
dec{8}q16 = 3.14E-5
dec{8}q17 = 6.5E9
dec{0}q2 = 3
dec{4}q3 = 3.1416
dec{8}q4 = 3.14159265
dec{12}q5 = 3.141592651416
dec{16}q6 = 3.1415926514159265
dec{18}q7 = 3.141592651415926514
decr1 = 3.141592651415926514
还算满意。

你可能感兴趣的:(PowerBuilder)