[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
这里面要仔细追究也是说来话长。为什么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
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就是采用的这种模式。两者在正数上是一致的,区别就在于对负数取整的不同行为。这里就不再展开了。编程语言具体采用哪种方式都有诸多的原因。不过无论用哪种方式,都有大坑在等着……
[i=s] 本帖最后由 hzhh95963 于 2015-3-10 00:59 编辑
Pat 发表于 2015-3-10 00:53
对于C++这种rounding towards zero的好像可以用这种方式达到rounding half away from zero?
…
好像没错,我再验证一下
hzhh95963 发表于 2015-3-10 00:57
你把正数带进去算又不对了……
这个式子对于正数就是(int) (foo + 0.5)啊{:4_114:}
…
我跑了一下好像没发现什么问题…当然(int)改成static_cast
Pat 发表于 2015-3-10 01:00
这个式子对于正数就是(int) (foo + 0.5)啊
我跑了一下好像没发现什么问题…当然(int)改成stati …
{:4_114:}我开始算的时候脑抽了……后来发现确实没错……
PHP算个P世界上最好的语言?

你又想挑起战【关键词】争了吗
门矢风湿 发表于 2015-3-10 01:07
PHP算个P世界上最好的语言?
你又想挑起战【关键词】争了吗
hzhh95963 发表于 2015-3-10 00:21
你把负数作为参数放进去算算看是什么结果……
Java就是用了这种偷懒的做法…… …
数学上-10.5四舍五入就是-10啊?“入“的意思就是向上取,-10比-10.5大的
wakawakashine 发表于 2015-3-10 01:43
数学上-10.5四舍五入就是-10啊?“入“的意思就是向上取,-10比-10.5大的
http://en.wikipedia.org/wiki/Rounding#Round_half_away_from_zero
四舍五入是为了精度考虑的,你让负数反而取偏差大的算什么情况……
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
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?
hzhh95963 发表于 2015-3-10 02:26
你知道你自己在说什么吗………
10.6往上“入”变成11对不对?10.5和10.6的行为一致,都是“入”对不对? …
-10.6是向下舍成为-11的,四舍五入这个词语只适用于正数,如果想适用负数更准确应该叫就近取整
wakawakashine 发表于 2015-3-10 02:32
-10.6是向下舍成为-11的,四舍五入这个词语只适用于正数,如果想适用负数更准确应该叫就近取整 …
{:4_110:}虽然不太懂,但是感觉你们走远了
wakawakashine 发表于 2015-3-10 02:32
-10.6是向下舍成为-11的,四舍五入这个词语只适用于正数,如果想适用负数更准确应该叫就近取整 …
说得没错,就近取整,所以你想清楚5距离哪里近了吗……
hzhh95963 发表于 2015-3-10 02:36
说得没错,就近取整,所以你想清楚5距离哪里近了吗……
数学上用的是towards positive infinity方式的round,java也是一样,而sqlserver等常见数据库用的是away from zero方式的round,这个是你说的那种,严格意义上不是四舍五入,而是绝对值的四舍五入
@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:}
Pat 发表于 2015-3-10 02:50
@hzhh95963 @wakawakashine
二位没什么好争的吧…关于0.5的问题,因为到前后两个整数的距离相同,所以 …
其实我只是想吐槽一下曾经把我坑死的四舍五入这个词,数学上用的竟然是round half up策略
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……
wakawakashine 发表于 2015-3-10 02:55
其实我只是想吐槽一下曾经把我坑死的四舍五入这个词,数学上用的竟然是round half up策略 …
具体四舍五入指的是哪种策略,感觉还是有些争议呢…如果按照中文的wiki来说,其将四舍五入理解为round half up,因为有“造成结果的系统偏高,误差偏大”一句。不过round half away from zero也许是更好的策略?嘛,各有所长吧。
其实…我觉得如果我是角川的程序员,在了解完这么多令人头大的取整策略后,我也会直接用(int)的…反正取整了就好,又不是什么实验计算,爱谁谁…
Pat 发表于 2015-3-10 02:50
@hzhh95963 @wakawakashine
二位没什么好争的吧…关于0.5的问题,因为到前后两个整数的距离相同,所以 …
{:4_102:}PHP,世界上最好的编程语言。
[s]我才不会告诉你我在本科用PHP写了一个数据库大作业之后下定决心以后再也不碰它了[/s]
虽然看不懂,还是顶一下
Pat 发表于 2015-3-10 03:02
具体四舍五入指的是哪种策略,感觉还是有些争议呢…如果按照中文的wiki来说,其将四舍五入理解为round h …
四舍五入只有一种规则,不过说到取整的话根据不同需要走不同规则就好了,不一定非要四舍五入,程序语言里也都不一样,fortran取整只取整数部分主要是为了数学上方便取余运算,余数就是a1-a2*int(a1/a2),算是补充楼主观点吧
PHP那句为啥要加特效弄得很粗很大{:4_114:}
LZ你这是要挑起战【关键词】争吗!
水得好!!!
我说你只是无聊想挑起战【关键词】争吧 233333
完全看不懂这是在说什么,但是不是说我们惯用的公式其实需要做些更正呢?
_(:зゝ∠)_我光看那句世界上最好的程序语言了
程序猿水贴{:4_90:}
为什么不干脆用浮点型计算。。。
现在多数RTS都是用浮点做生命,整型来显示。虽然有0血不死的现象
(o·_·)ノ能看懂C++版本的,好久不弄C语言了..
萌新快被dalao吓趴了。{:4_115:}
凡人看只能坐在地上看天庭众神之间撕逼。{:4_102:}
懒到条蛇咁 发表于 2015-3-10 07:39
我说你只是无聊想挑起战【关键词】争吧 233333
{:4_96:}被看穿了