ABAP中的向上取整函数Ceil( )使用注意事项(decfloat16 & decfloat34)

本文揭示了ABAP中Ceil函数与整型运算的潜在问题,探讨了如何避免四舍五入误差。通过实例演示了使用不同数据类型(如int8、decfloat16)来确保正确向上取整,以及推荐的解决方案和适用场景。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1. 问题的提出

Ceil( )是ABAP的向上取整函数,然在在使用中,还是要留意数据类型的问题哦。先看下面代码:

DATA lv_result_1 TYPE i.
DATA lv_result_2 TYPE i.
DATA lv_count_1 TYPE i VALUE '3600'.
DATA lv_count_2 TYPE i VALUE '3001'.
DATA lv_size TYPE i VALUE '1000'.

lv_result_1 = ceil( lv_count_1 / lv_size ).
lv_result_2 = ceil( lv_count_2 / lv_size ).

WRITE:/ 'Result 1 is: ' && lv_result_1.
WRITE:/ 'Result 2 is: ' && lv_result_2.

猜一猜结果?

3600 / 1000的结果是3.6 , 向上取整应该是 4;
3001 / 1000的结果是3.001,向上取整也应该是 4。

但实际的结果呢?第一个是4, 第二个却是3。问题出在哪了?
在这里插入图片描述

2. 数字类型的ABAP变量

在ABAP中有以下几种常见的数字类型的变量:

类型长度描述
i4 byte整形,只能存储整数,范围 -2,147,483,648 to +2,147,483,647 (推荐使用)
int88 byte长整形,只能存储整数,范围 -9,223,372,036,854,775,808 to +9,223,372,036,854,775,807(推荐使用)
f8 byte二进制浮点数,可存储小数(f类型会有些问题,现在已不建议再使用此类型)
p1 ~ 16 byte压缩数类型,可存储小数,自定义长度和小数点位数 (尽量用decfloat16和decfloat34替代)
decfloat168 byte十进制浮点数,可最长有16位小数位(推荐使用)
decfloat3416 byte十进制浮点数,可最长有34位小数位(推荐使用)

看完此处的总结,便可以分析上例Ceil( )的运算结果的原因了。

lv_result_1 = ceil( lv_count_1 / lv_size ).
lv_result_2 = ceil( lv_count_2 / lv_size ).

这里面的运算数都是整形,因此在ceil( )运算后,发生了隐式的“四舍五入”。需要注意的是,此处即使是动态声明结果变量,其结果还是一样的。

data(lv_result_1) = ceil( lv_count_1 / lv_size ).
data(lv_result_2) = ceil( lv_count_2 / lv_size ).

因为ceil( )运算返回个结果数据类型为整形,所以,动态声明出来的变量也会是整形,在接收结果时还是会发生“四舍五入”。

3. 解决办法

了解完原理,其解决办法也很简单,也即在Ceil( )时,要保证中间结果是“小数类型”。看下例:

DATA lv_upper_result TYPE i.
DATA lv_float_result TYPE p LENGTH 8 DECIMALS 3.
DATA lv_count TYPE i VALUE '3001'.
DATA lv_size TYPE i VALUE '1000'.

lv_float_result = lv_count / lv_size.
lv_upper_result = ceil( lv_float_result ).

WRITE:/ 'Float result is: ' && lv_float_result.
WRITE:/ 'Upper result is: ' && lv_upper_result.

这样就保证接收到的“除法运算”结果为小数,在小数的基础上,再向上取整,便不会发生“四舍五入”的意外。
运行结果为:
在这里插入图片描述
p类型的使用需要指定长度和小数位,并不是最优的解决方法,在较高版本的Netwear上,更推荐使用decfloat16和decfloat34这两种类型,它们可以动态地拓展所需要的小数位,并不需要手动指定。

代码如下:

DATA lv_upper_result TYPE i.
DATA lv_float_result TYPE decfloat16. " decfloat34
DATA lv_count TYPE i VALUE '3001'.
DATA lv_size TYPE i VALUE '1000'.

lv_float_result = lv_count / lv_size.
lv_upper_result = ceil( lv_float_result ).

WRITE:/ 'Float result is: ' && lv_float_result.
WRITE:/ 'Upper result is: ' && lv_upper_result.

当然,我们可以用动态声明变量的方式,将这段代码写的更简洁:

DATA lv_count TYPE i VALUE '3001'.
DATA lv_size TYPE i VALUE '1000'.

DATA(lv_float_result) = CONV decfloat16( lv_count / lv_size ).
DATA(lv_upper_result) = ceil( lv_float_result ).

WRITE:/ 'Float result is: ' && lv_float_result.
WRITE:/ 'Upper result is: ' && lv_upper_result.

其实,也可以再夸张一点:

DATA lv_count TYPE i VALUE '3001'.
DATA lv_size TYPE i VALUE '1000'.

DATA(lv_upper_result) = ceil( CONV decfloat16( lv_count / lv_size ) ).

WRITE:/ 'Upper result is: ' && lv_upper_result.

运行结果:
在这里插入图片描述

怎么样?通过以上的解析,你清楚了么 😉

本博客专注于技术分享,干货满满,持续更新。
欢迎关注❤️、点赞👍、转发📣!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

十年铸器

给作者赏杯咖啡

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值