我一直在网上寻找如何将 Oracle 数字转换成我可以使用的东西,但是我完全找不到任何人设法想出一个完整的算法(特别是负指数) .
一些信息已发布在 https://gotodba.com/2015/03/24/how-are-numbers-saved-in-oracle/ 上然而,这是不完整的,因为它无法描述负指数解决方案,其中必须再次位翻转。下面是我想出的代码,使它能够成功处理(到目前为止)。我测试了从 -10,000 到 999,999 和 0.0001 到 2.0002 的值。
struct ValueExponent {
int64_t value = 0;
int32_t exponent = 0; // Powers of 10
};
int32_t CalculateExponent(const ::oracle::occi::Bytes& bytes, bool& isNegative) {
int workingExponent = static_cast<int>(bytes.byteAt(0));
isNegative = (workingExponent & 0x80) == 0;
if (isNegative)
workingExponent = ~workingExponent;
bool isNegativeExponent = (workingExponent & 0x40) == 0;
if (isNegativeExponent)
workingExponent = ~workingExponent;
return ((isNegativeExponent ? -1 : 1) * (workingExponent & 0x3f)) - (isNegativeExponent ? 1 : 0);
}
ValueExponent OracleNumberToValueExponent(const ::oracle::occi::Number& num) {
auto bytes = num.toBytes();
int64_t value = 0;
bool isNegative = false;
int32_t exponent = CalculateExponent(bytes, isNegative);
decltype(bytes.length()) max = isNegative ? bytes.length() - 1 : bytes.length();
for(decltype(bytes.length()) ix = 1; ix < max; ++ix) {
auto borig = bytes.byteAt(ix);
int b = static_cast<int>(borig);
b -= 1;
if (isNegative)
b = 100 - b;
value = value * 100 + b;
--exponent;
}
ValueExponent retval;
retval.value = isNegative ? -value : value;
retval.exponent = exponent * 2; //Oracle exponents are of 100 not 10
return retval;
}
我相信这应该能够输出任何需要的东西,但如果有人能提供改进算法的建议,我们将不胜感激。
最佳答案
假设您的数字来自数据库,您可以在字符串上应用逻辑,而不是重新发明如何导出值和指数,例如:
WITH nums AS (SELECT -10000 nbr from dual UNION ALL
SELECT -0.99 nbr FROM dual UNION ALL
SELECT 0 nbr FROM dual UNION ALL
SELECT 0.0001 nbr FROM dual UNION ALL
SELECT 0.99 nbr FROM dual UNION ALL
SELECT 2.0002 nbr FROM dual UNION ALL
SELECT 999999 nbr FROM dual UNION ALL
SELECT 1e23 nbr FROM dual)
SELECT nbr,
sci_num,
TO_NUMBER(SUBSTR(sci_num, 1, INSTR(sci_num, 'E', 1, 1) - 1)) val,
TO_NUMBER(SUBSTR(sci_num, INSTR(sci_num, 'E', 1, 1) + 1)) EXP
FROM (SELECT nbr,
to_char(nbr, 'fm0D099999999999999999EEEE') sci_num
FROM nums);
NBR SCI_NUM VAL EXP
---------- -------------------------- ---------- ----------
-10000 -1.0E+04 -1 4
-0.99 -9.9E-01 -9.9 -1
0 0.0E+00 0 0
0.0001 1.0E-04 1 -4
0.99 9.9E-01 9.9 -1
2.0002 2.0002E+00 2.0002 0
999999 9.99999E+05 9.99999 5
1E23 1.0E+23 1 23
(nums
子查询只是一种生成一些测试数据以在查询中使用的方法。)
如果你需要在 PL/SQL 中实现这个逻辑,你可以这样做:
DECLARE
v_num NUMBER := -10001;
v_val NUMBER;
v_exp NUMBER;
v_sci_fmt_num VARCHAR2(100);
BEGIN
v_sci_fmt_num := to_char(v_num, 'fm0D099999999999999999EEEE');
v_val := TO_NUMBER(SUBSTR(v_sci_fmt_num, 1, INSTR(v_sci_fmt_num, 'E', 1, 1) - 1));
v_exp := TO_NUMBER(SUBSTR(v_sci_fmt_num, INSTR(v_sci_fmt_num, 'E', 1, 1) + 1));
-- dummy output
dbms_output.put_line('number: '||v_num||'; value = '||v_val||', exponent = '||v_exp);
END;
/
number: -10001; value = -1.0001, exponent = 4
关于c++ - 将 Oracle 的数字转换为字节,然后转换为值 + 指数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57722874/