c\c++ 中存储 COM VT_DECIMAL的正确类型是什么?
What is the correct type in cc++ to store a COM's VT_DECIMAL?
我正在尝试为ADO编写一个包装器。
当VARIANT
类型是VT_DECIMAL
时,DECIMAL
是COM VARIANT
可以是的一种类型。
我试图将它放在c本机数据类型中,并保留变量值。似乎正确的类型是长双,但我得到"没有合适的转换错误"。
例如:
_variant_t v;
...
if(v.vt == VT_DECIMAL)
{
double d = (double)v; //this works but I'm afraid can be loss of data...
long double ld1 = (long double)v; //error: more then one conversion from variant to long double applied.
long double ld2 = (long double)v.decVal; //error: no suitable conversion function from decimal to long double exist.
}
所以我的问题是:
使用double来存储所有可能的十进制值是否完全安全?
如果没有,我如何将小数转换为长的双精度?
如何将十进制转换为字符串?(使用<<运算符,
sprintf
对我也有好处)
DECIMAL
的内部表示不是双精度浮点值,而是带有符号/小数选项的整数。如果要初始化DECIMAL
部分,则应该初始化这些字段-96位整数值、小数位数、符号,然后获得有效的十进制VARIANT
值。
MSDN上的DECIMAL
:
- scale—数字的小数位数。有效值介于0到28之间。因此12.345表示为12345,标度为3
- 符号-表示符号;0表示正数,DECIMAL_EG表示负数。因此,-1表示为1,并设置了DECIMAL_NEG位
- Hi32-数字的高32位
- Lo64-数字的低64位。这是一个_int64
您的问题:
使用double来存储所有可能的十进制值是否完全安全?
不能直接初始化为double(例如VT_R8
),但可以初始化为doublevariant,并使用variant转换API转换为VT_DECIMAL
。可以对值进行小的舍入。
如果没有,我如何将小数转换为长的双精度?
如何将十进制转换为字符串?(使用<<运算符,sprintf对我也有好处)
VariantChangeType
可以将十进制变量转换为其他类型的变量,包括整数、双精度、字符串-您可以提供要转换的类型。反之亦然,您也可以将不同的内容转换为十进制。
"安全"这个词并不完全正确,DECIMAL的要点是不会因基数转换而引入舍入误差。计算是以基数10而不是基数2进行的。这使得它们缓慢但准确,这是会计师喜欢的准确性。他将不必去追求十亿分之一便士的不匹配。
使用_variant_t::ChangeType()进行转换。通过VT_R8
转换为双精度。通过VT_BSTR
转换成字符串,会计喜欢的那种。追逐long double
毫无意义,10字节FPU类型已经成为历史。
这个片段取自http://hackage.haskell.org/package/com-1.2.1/src/cbits/AutoPrimSrc.c
Hackage.org说:
Hackage是Haskell社区开放的中心包档案源软件。
但是请检查作者权限
void writeVarWord64( unsigned int hi, unsigned int lo, VARIANT* v )
{
ULONGLONG r;
r = (ULONGLONG)hi;
r >>= 32;
r += (ULONGLONG)lo;
if (!v) return;
VariantInit(v);
v->vt = VT_DECIMAL;
v->decVal.Lo64 = r;
v->decVal.Hi32 = 0;
v->decVal.sign = 0;
v->decVal.scale = 0;
}
如果我理解微软的文档(https://msdn.microsoft.com/en-us/library/cc234586.aspx)正确地说,VT_DECIMAL是一个精确的92位整数值,具有固定的小数位数和精度。在这种情况下,您无法将其存储在浮点、双精度或64位整数变量中而不丢失信息。
你最好把它存储在一个128位整数中,比如__int128,但我不知道编译器对它的支持程度。我也不确定你是否能够在不进行一些位操作的情况下将一个转换为另一个。
使用double来存储所有可能的十进制值是否完全安全?
这实际上取决于你所说的安全是什么意思。如果你的意思是"存在引入某种程度的转换不精确的风险吗?",是的,存在风险。内部表示差异太大,无法保证完美的转换,并且可能会引入转换噪声。
如何将小数转换为长双精度/a字符串?
它(再次)取决于你想对对象做什么:
- 有关浮点计算,请参阅@Gread.And.Powermed.Oz链接到以下答案:C++将Variant Decimal转换为Double Value
- 有关显示,请参阅MSDN关于字符串转换的文档
对于没有任何转换不精确性的存储,您可能应该将小数存储为形式为pair<long long,short>
的缩放整数,其中first
保存96位尾数,second
保存小数点右侧的位数。这种表示尽可能接近十进制的内部表示,不会引入任何转换不精确性,也不会在整数到字符串格式化上浪费CPU资源。
- 为不同配置设置MSVC_RUNTIME_LIBRARY的正确方法是什么
- C++避免重复声明的语法是什么
- 在C++中,将大的无符号浮点数四舍五入为整数的最佳方法是什么
- 实现无开销push_back的最佳方法是什么
- C++从另一个类访问公共静态向量的正确方法是什么
- "throw expression code" 1e7 >返回 d 是什么?投掷标准::overflow_error( "too big" ) : d;意味 着?
- C++中名称篡改的目的是什么
- 在 c++ 中拥有一组结构的正确方法是什么?
- 这个指针和内存代码打印是什么?我不知道是打印垃圾还是如何打印我需要的值
- 是什么阻止DOMTimerCoordinator::NextID进入无休止的循环
- 派生类销毁的最佳实践是什么
- 这个语法std::class<>{}(arg1, arg2) 在C++中是什么意思?
- 通过JNI传递数据数组的最快方法是什么
- "using namespace std;"在C++的作用是什么?
- 在两台机器之间进行时间戳的最佳c++chrono函数是什么
- 文件系统:复制功能的速度秘诀是什么
- 用常见虚拟函数实现的任意组合来实现派生类的正确方法是什么
- 使用QQuickFramebufferObject时同步数据的最佳方式是什么
- 是什么原因导致它无法编译?它是声明签名还是在函数本身的实现中
- 使用不同的CRT将新的C++代码与旧的(二进制)组件隔离开来的最佳方法是什么