问题记录
日常运维工作中,遇到了销售订单定价例程增强计算异常的bug。P类型的金额字段在计算时会异常地放大与缩小,并且在计算过程中丢失小数位精度。
问题分析
经查询分析,发现销售订单的增强大部分是基于源代码的增强,大部分增强是写在包含文件MV45AFZZ中,对各个USER_EXIT开头的子例程进行增强。而销售订单定价例程也是类似,用户自定义的例程增强公式,都会记录在包含文件RV64ANNN中,新增公式时在其中插入INCLUDE语句从而生效。
我们可以通过SE38查看两个包含文件的属性,发现均未启用固定点算术。
在日常开发的可执行程序中,我们会默认勾选固定点算术选项,所以计算过程是正常的,这里我们查看SAP官方文档解释。
这里理解为勾选固定点算术时,就是基于真实的数值进行计算;而未勾选时会忽略小数位将数值视为正整数计算,导致精度丢失与数值异常。
接下来我们新建一个DEMO验证:
DATA: lv_p_2 TYPE p DECIMALS 2,
lv_p_6 TYPE p DECIMALS 6.
" 根据小数位进行放大缩小
lv_p_2 = 123 * 100.
lv_p_6 = 123 * 1000000.
cl_demo_output=>write( lv_p_2 ).
cl_demo_output=>write( lv_p_6 ).
" 计算结果转为正整数
lv_p_2 = '123' / '2'. " 123 / 2 = 61.5
cl_demo_output=>write( lv_p_2 ).
cl_demo_output=>display( ).
运行结果:
可以发现,在非固定点算术的程序中,两位小数的P类型字段会缩小100倍,需要乘100才能得到真实值,而六位小数的P类型字段会缩小100000倍。
在计算时,'123/2'的计算结果为61.5,会被转为正整数62,同时因为两位小数导致缩小100倍变为了0.62,即使此时乘以100的放大倍数得到62,也产生了0.5的差异。
解决方案
这是一代增强的遗留问题,SD模块对于销售订单/定价/交货单常用一代增强,而源程序属性大多数未勾选固定点算术,在这种情况下计算精度会受到影响,同时也无法使用ABAP SQL的新特性,例如无法使用内联声明便捷创建局部变量/内表。
所以在做一代增强时,建议使用类/函数对增强逻辑进行二次封装,使增强逻辑在固定点算术的环境中运行即可修复异常。