Excel 2010 与 Excel 2003 中的整数表示(C++ 插件)
Posted
技术标签:
【中文标题】Excel 2010 与 Excel 2003 中的整数表示(C++ 插件)【英文标题】:Representation of integers in Excel 2010 vs Excel 2003 (C++ plugin) 【发布时间】:2012-12-07 11:37:06 【问题描述】:简介
我继承了一个使用 VS2008、xlw 2.0 和 excel 2003 开发的遗留插件项目(C++)。
我已设法将它移植到 xlw 4.0 标头(添加对 Excel 2007 的支持时,某些方法更改了名称,诸如此类)。我没有生成任何东西(还),因为旧代码是手工编写的,我不会更改正在运行的东西,并且只是为了它而具有合理的结构和代码逻辑。
代码在 excel 2003 下按预期工作。我今天尝试使用 excel 2010 并发现了一个最令人费解(和可怕)的错误。
令人费解的行为
我(从 VBA 宏)接收一列(n 行,1 列)数字(通过构造的小正整数)作为 XlfOper & 我想将其转换为(旧式)数组。代码基本上遍历每一行,然后在与给定行对应的 XlfOper 上调用 AsInt() 方法。比如:
for (long iy = 0; iy < numcols; ++iy)
for (long ix = 0; ix < numrows; ++ix)
convertXflOper( x(ix, iy), a1D[iy*numrows + ix] );
其中 a1D 是此特定项目中使用的一维数组类型,convertXflOper 是模板函数,适用于这些类型:
void convertXflOper (const XlfOper &x, long & y)
y = x.AsInt();
在给定的行中,我在 excel 工作簿中有数字 10。
在 Excel 2003 下,此值转换为 10。在 Excel 2010 下,此值转换为 9。
我已经对其进行了调试,问题是它实际上读取的不是 10,而是它的双重近似值。 (即时窗口的)输出是
x.lpxloper4_->val.num
9.9999999999999982 // wrong: I am not asking for 10.0, I am asking for 10
在 Excel 2010 中,以及
x.lpxloper4_->val.num
10.000000000000000 // right: an integer is an integer
在 Excel 2003 中。因此,尽管 C++ 代码很漂亮(或不漂亮),但似乎没有错。 AsInt() 方法的行为类似于强制转换,static_cast<long>(9.9999999999999982)
是 9,而不是 10。
问题
这件事让我很伤心,主要是因为它很容易被忽视:对于许多其他整数值,它在 excel 2003 和 2010 中都能正常工作。
我在 excel 界面中做错了什么,因为它认为整数必须被视为双精度数?我怎么能确定这不会在谁知道何时何地发生?解决此问题的最佳方法是什么?
【问题讨论】:
我认为 excel 在内部处理浮点数是有意义的。也许在新版本的 excel 中舍入的内部行为发生了变化。如果您可以访问x.AsDouble();
之类的方法,您应该自己简单地进行舍入。
@Fermat2357 很好,但是整数应该被精确表示,这似乎是一个基本的期望。我可以使用这种方法,问题是确保我在可能需要它的所有情况下都应用它......这种动态输入不容易预测何时需要出现,并确保手动转换适用于任何地方。
是的,你是对的。足够小的整数可以精确地表示为双精度数。如果我们假设预期的整数是浮点格式的非常接近的近似值,那么将舍入方法应用于转换为整数应该可以正常工作。如果我们不能假设这一点,你就有麻烦了。你至少应该测试一下。
那个单元格的公式是什么?似乎在某个地方它涉及一些不返回整数的数学。
@MarkRansom 不错的猜测:但它是一个静态值。它基本上是计算行中大于零的单元格的数量,但不是公式:它是由(以前的,独立的)宏写为值。
【参考方案1】:
Excel 内部不保存整数 - 所有数字(整数、日期、时间、货币等)都保存为双精度数。因此,Oper val.num 始终是双精度数,而 xltypeNum 的操作数始终是双精度数。(操作员可以在 val.w 中保存整数,但只能作为 XLM 宏流控制之类的东西的一部分,这些东西已经过时了几十年并且在实践中不太可能满足)。 我不知道为什么您在 Excel 2007 中得到 9.9999999 - 您如何将值传递给 Oper?
【讨论】:
谢谢@CharlesWilliams。这也是我(尽管有限)的理解。 XlfOper 是这样传递的: Run("my_dll_function", Application.Run(a_worksheet_name & a_VBA_function_returning_a_range));有问题的函数只是设置 a_function.... = ThisWorkbook.Sheets(....).Range("my_range_name") 由于数字来自一个单元格,它最初是一个双精度数。从命名范围中获取值似乎是一条非常迂回的路线,可能会进行多次转换,但我认为这是有原因的。您是否尝试过在 XL 2007 中使用 Oper12 来查看是否会发生同样的事情?以上是关于Excel 2010 与 Excel 2003 中的整数表示(C++ 插件)的主要内容,如果未能解决你的问题,请参考以下文章
Excel 2003 XML 格式不会在 Excel 2010 x64 中自动打开
Excel 2003 与 Excel 2007之间有什么不同?
如何使用vba在excel2010中将保存类型从excel工作簿更改为excel 97-2003?