hzhh95963

蓝猫淘气三千问:为什么舰C里面不使用四舍五入?

[i=s] 本帖最后由 hzhh95963 于 2015-3-10 00:05 编辑

看到不少提督在计算火力和伤害等数值的时候,在无意中使用了四舍五入的取整方式。但是事实上,舰C的取整全部是向下取整(或向零取整,后面会提)这是为何呢?

那么我们来看一看计算机是如何处理取整这个操作的。常见的C语言来实现取整:

[code]// C sytle

float foo = 10.6;

int bar = (int)foo; // bar == 10[/code]或

[code]// C sytle

float foo = 10.6;

int bar = int(foo); // bar == 10[/code]

或者是在C++更加推荐的方式:

[code]// C++ sytle

float foo = 10.6;

int bar = static_cast(foo); // bar == 10[/code]

这里面要仔细追究也是说来话长。为什么C/C++没有采用向最接近整数取整而是向零取整?

这个问题其实很尴尬……在C99以前,C语言的标准都没有明确规定到底应该怎么取整,这个问题被留给了编译器自己来决定。编译器选择的是向Fortran靠拢。(后来在C99,向零取整就变成了语言标准)。那么Fortran为什么又要那么取整呢?具体的原因我没有调查到。这其中应该有数学上的考量,也有对当时的硬件环境的考虑。毕竟Fortran诞生的时候,就连IEEE 754这个浮点数标准都还没有出现呢。然后C++为了兼容C语言,继承了这个设计……接下来Java这个C++的精神继任者也继续采用了这个设计……

不过舰娘的后台服务端一般不会是用C/C++来写的。那些动态语言们往往有其他的实现方式。

比如,我来看看用世界上最好的编程语言PHP怎么来实现这个[s](才不是)[/s]

[code] $foo = 10.6;

$bar = floor($foo); // $bar == 10

$bar = round($foo); // $bar == 11

$bar = intval($foo) // $bar == 10

?>[/code]floor和intval有什么区别?floor返回的是一个浮点型,intval返回的是一个整型,round和ceil返回的居然也是浮点型……

[s]我个人认为PHP的类型转换简直是个死亡雷区……[/s]

那么不要管PHP了,日本人发明的Ruby是什么情况呢?

[code]# Ruby

foo = 10.6

bar = foo.floor # bar == 10

bar = foo.round # bar == 11[/code]

嗯……这两个都很正常地返回了一个整型……

说了半天,舰C是什么情况?舰C似乎并没有像前面的动态语言那样有过四舍五入?我个人认为,舰C作为一个使用HTTP连接的页游,后台非常有可能是用Java写的:

[code]// Java

foo = 10.6;

int bar = (int)foo; // bar == 10[/code](好像有点眼熟)

看,是不是都挺简单的?那么如果要使用四舍五入规则呢?事实上,一直到C99和C++11之前,C/C++都没有一个round函数。好吧,我就只写一个C++版本的吧。

[code]// C++ sytle

float foo = 10.6;

int bar;

int floor = static_cast(foo);

if ((foo – floor) < 0.5 || (foo - floor) > -0.5) {

bar = floor;

} else {

bar = floor + ((foo > 0) – (foo < 0)); // bar == 11
}[/code]感觉效率不是很高的样子……

不过Java就更加残念了……它标准库里自带的Math.round的实现是错误的……把-10.5传给这个函数返回的结果是-10而不是-11……

另外还有一些更复杂的数值修约规则,比如“奇进偶舍”……要写的代码肯定就是更长了……除非采取某些特别tricky的办法,具体不再展开了……

那么,现在假设你是程序员来实现舰娘的服务器,你会选择哪种方式呢?

一些题外话

事实上,常用的编程语言有两种取整,一种是“向零取整”,向0方向取最接近的整数。C、C++、Java采用的就是这种模式。另一种是“向下取整”,向-∞方向取最接近的整数,Python、Ruby就是采用的这种模式。两者在正数上是一致的,区别就在于对负数取整的不同行为。这里就不再展开了。编程语言具体采用哪种方式都有诸多的原因。不过无论用哪种方式,都有大坑在等着……

发表回复

  1. hzhh95963说道:

    [i=s] 本帖最后由 hzhh95963 于 2015-3-10 00:59 编辑

    Pat 发表于 2015-3-10 00:53

    对于C++这种rounding towards zero的好像可以用这种方式达到rounding half away from zero?



    好像没错,我再验证一下

  2. Pat说道:

    hzhh95963 发表于 2015-3-10 00:57

    你把正数带进去算又不对了……

    这个式子对于正数就是(int) (foo + 0.5)啊{:4_114:}

    我跑了一下好像没发现什么问题…当然(int)改成static_cast

  3. hzhh95963说道:

    Pat 发表于 2015-3-10 01:00

    这个式子对于正数就是(int) (foo + 0.5)啊

    我跑了一下好像没发现什么问题…当然(int)改成stati …

    {:4_114:}我开始算的时候脑抽了……后来发现确实没错……

  4. 门矢风湿说道:

    PHP算个P世界上最好的语言?

    你又想挑起战【关键词】争了吗

  5. hzhh95963说道:

    门矢风湿 发表于 2015-3-10 01:07

    PHP算个P世界上最好的语言?

    你又想挑起战【关键词】争了吗

  6. wakawakashine说道:

    hzhh95963 发表于 2015-3-10 00:21

    你把负数作为参数放进去算算看是什么结果……

    Java就是用了这种偷懒的做法…… …

    数学上-10.5四舍五入就是-10啊?“入“的意思就是向上取,-10比-10.5大的

  7. hzhh95963说道:

    wakawakashine 发表于 2015-3-10 01:43

    数学上-10.5四舍五入就是-10啊?“入“的意思就是向上取,-10比-10.5大的

    http://en.wikipedia.org/wiki/Rounding#Round_half_away_from_zero

    四舍五入是为了精度考虑的,你让负数反而取偏差大的算什么情况……

  8. wakawakashine说道:

    hzhh95963 发表于 2015-3-10 01:50

    http://en.wikipedia.org/wiki/Rounding#Round_half_away_from_zero

    四舍五入是为了精度考虑的,你让负 …

    -10.5=-11+0.5这么看明白了吗?四舍五入向上入当然是-11+1=-10,同理例如-10.6=-11+0.4,向下舍取-11

  9. hzhh95963说道:

    wakawakashine 发表于 2015-3-10 02:17

    -10.5=-11+0.5这么看明白了吗?四舍五入向上入当然是-11+1=-10,同理例如-10.6=-11+0.4,向下舍取-11 …

    你知道你自己在说什么吗………

    10.6往上“入”变成11对不对?10.5和10.6的行为一致,都是“入”对不对?加个负号就不懂了?-10.6“入”了,变成-11,-10.5你要怎么“入”才能“入”成-10?

  10. wakawakashine说道:

    hzhh95963 发表于 2015-3-10 02:26

    你知道你自己在说什么吗………

    10.6往上“入”变成11对不对?10.5和10.6的行为一致,都是“入”对不对? …

    -10.6是向下舍成为-11的,四舍五入这个词语只适用于正数,如果想适用负数更准确应该叫就近取整

  11. qhdasd说道:

    wakawakashine 发表于 2015-3-10 02:32

    -10.6是向下舍成为-11的,四舍五入这个词语只适用于正数,如果想适用负数更准确应该叫就近取整 …

    {:4_110:}虽然不太懂,但是感觉你们走远了

  12. hzhh95963说道:

    wakawakashine 发表于 2015-3-10 02:32

    -10.6是向下舍成为-11的,四舍五入这个词语只适用于正数,如果想适用负数更准确应该叫就近取整 …

    说得没错,就近取整,所以你想清楚5距离哪里近了吗……

  13. wakawakashine说道:

    hzhh95963 发表于 2015-3-10 02:36

    说得没错,就近取整,所以你想清楚5距离哪里近了吗……

    数学上用的是towards positive infinity方式的round,java也是一样,而sqlserver等常见数据库用的是away from zero方式的round,这个是你说的那种,严格意义上不是四舍五入,而是绝对值的四舍五入

  14. Pat说道:

    @hzhh95963 @wakawakashine

    二位没什么好争的吧…关于0.5的问题,因为到前后两个整数的距离相同,所以人为地规定了不同的策略来定义0.5时如何rounding,而你们说的只是两种不同策略,没有谁对谁错之分,实际应用的时候也都有出现…

    @hzhh95963 用的是round half away from zero策略,也就是找最近的整数,如果出现x.5的情况则选离0远的整数;

    @wakawakashine 用的是round half up策略,同样在找最近整数的基础上,遇到x.5则找大于改值的最近整数。

    round half up策略的优势是计算简单,不用分符号讨论,但是是非对称的rounding,会改变数值的期望,这点round half away from zero不会。

    最后,世界上最好的编程语言是个什么鬼啊!{:4_113:}

  15. wakawakashine说道:

    Pat 发表于 2015-3-10 02:50

    @hzhh95963 @wakawakashine

    二位没什么好争的吧…关于0.5的问题,因为到前后两个整数的距离相同,所以 …

    其实我只是想吐槽一下曾经把我坑死的四舍五入这个词,数学上用的竟然是round half up策略

  16. hzhh95963说道:

    wakawakashine 发表于 2015-3-10 02:44

    数学上用的是towards positive infinity方式的round,java也是一样,而sqlserver等常见数据库用的是away …

    所以你没看出来我是在黑Java吗……

    大部分编程语言实现Round half away from zero的地方,它给实现一个Round half up。最搞笑的地方是Java在BigDecimal里面实现了一个Round half away from zero,结果还把这个叫Round half up……

  17. Pat说道:

    wakawakashine 发表于 2015-3-10 02:55

    其实我只是想吐槽一下曾经把我坑死的四舍五入这个词,数学上用的竟然是round half up策略 …

    具体四舍五入指的是哪种策略,感觉还是有些争议呢…如果按照中文的wiki来说,其将四舍五入理解为round half up,因为有“造成结果的系统偏高,误差偏大”一句。不过round half away from zero也许是更好的策略?嘛,各有所长吧。

    其实…我觉得如果我是角川的程序员,在了解完这么多令人头大的取整策略后,我也会直接用(int)的…反正取整了就好,又不是什么实验计算,爱谁谁…

  18. hzhh95963说道:

    Pat 发表于 2015-3-10 02:50

    @hzhh95963 @wakawakashine

    二位没什么好争的吧…关于0.5的问题,因为到前后两个整数的距离相同,所以 …

    {:4_102:}PHP,世界上最好的编程语言。

    [s]我才不会告诉你我在本科用PHP写了一个数据库大作业之后下定决心以后再也不碰它了[/s]

  19. 中津静流丶说道:

    虽然看不懂,还是顶一下

  20. wakawakashine说道:

    Pat 发表于 2015-3-10 03:02

    具体四舍五入指的是哪种策略,感觉还是有些争议呢…如果按照中文的wiki来说,其将四舍五入理解为round h …

    四舍五入只有一种规则,不过说到取整的话根据不同需要走不同规则就好了,不一定非要四舍五入,程序语言里也都不一样,fortran取整只取整数部分主要是为了数学上方便取余运算,余数就是a1-a2*int(a1/a2),算是补充楼主观点吧

  21. ejade说道:

    PHP那句为啥要加特效弄得很粗很大{:4_114:}

    LZ你这是要挑起战【关键词】争吗!

  22. akasakisan说道:

    水得好!!!

  23. 懒到条蛇咁说道:

    我说你只是无聊想挑起战【关键词】争吧 233333

  24. Ctrl_Dagon说道:

    完全看不懂这是在说什么,但是不是说我们惯用的公式其实需要做些更正呢?

  25. 日始之音说道:

    _(:зゝ∠)_我光看那句世界上最好的程序语言了

  26. 南方棲戰姬说道:

    程序猿水贴{:4_90:}

  27. Bismarck改说道:

    为什么不干脆用浮点型计算。。。

    现在多数RTS都是用浮点做生命,整型来显示。虽然有0血不死的现象

  28. U-511说道:

    (o·_·)ノ能看懂C++版本的,好久不弄C语言了..

  29. WindExecutor说道:

    萌新快被dalao吓趴了。{:4_115:}

    凡人看只能坐在地上看天庭众神之间撕逼。{:4_102:}

  30. hzhh95963说道:

    懒到条蛇咁 发表于 2015-3-10 07:39

    我说你只是无聊想挑起战【关键词】争吧 233333

    {:4_96:}被看穿了

官方微信

Login

跳至工具栏