c\c++ 中存储 COM VT_DECIMAL的正确类型是什么?

What is the correct type in cc++ to store a COM's VT_DECIMAL?

本文关键字:是什么 DECIMAL 类型 c++ 存储 COM VT      更新时间:2023-10-16

我正在尝试为ADO编写一个包装器。

VARIANT类型是VT_DECIMAL时,DECIMALCOM 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.  
}

所以我的问题是:

  1. 使用double来存储所有可能的十进制值是否完全安全?

  2. 如果没有,我如何将小数转换为长的双精度?

  3. 如何将十进制转换为字符串?(使用<<运算符,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资源。