起点没有公布计数系统的统计标准。所以就有了本文,我们来猜一猜嘛。
在书架上随手找了一本之前订阅过的书,找了章公众章节。如下所示,共858字。
找个在线的OCR把图片识别成文字,再手动检查一遍,确保没有错漏。然后使用javaString的length()方法看看。为了方便感兴趣的同学,我把识别出来的文字也发出来。
几个猜测,首先中文的任意字,字符肯定是算1个字符长度的,比如!,(,),。,甚至中文多个句号当省略号。。。。。。也会被计算为6个字。然后英文单词只会计算成一个长度。其次英文输入法中的...也只会计算一个长度。
暴力点,直接先来一波验证一下。
以下测试代码将英文输入法下的...替换成一个字符,然后将连续的数字和英文单词(包含创造出的网络词汇英文缩写,或者叫连接的英文字母,拼音)也当成一个字符长度。具体做法是先替换为空,再在后边统计的时候补上个数。
Stringtemp=text.trim().replace("...",".").replace("..",".");Strings="\\d+.\\d+|\\w+";Patternpattern=Pattern.compile(s);Matcherma=pattern.matcher(temp);List
这章的标题是4个字,如果是标题的原因,那应该是差4个字,所以标题应该是不计数的。
也有可能是图片转文字的差异,可能是一些符号()不太容易分辨是哪种输入法,还有看不出来是分隔符还是破折号的"———"造成的差异。
更直接点,我下载了一个起点的作家助手,将上述文字直接输到公众章节,让起点计数系统统计,结果与我本地代码统计是一样的。
从侧面证明上述的猜测是对的。
所以起点真就是这样直接使用String.length()计算出来的?
为了更加的严谨,我再添加了一部小说,《重生之不做程序员》。
第一章《英雄迟暮》,正文内容为“SUN公司被Oracle收购,是否意味着java被逼上了死路?”
Stringtext2="sum公司被Oracle收购,是否意味着java被逼上了死路?";Stringtemp=text2.trim().replace("...",".").replace("..",".");Strings="\\d+.\\d+|\\w+";Patternpattern=Pattern.compile(s);Matcherma=pattern.matcher(temp);List
特殊字符呢?比如它被算作了两个字符。
为什么呢?直接复制过去,可以看到它是两个UTF16编码。所以长度为2。String.length()其实统计的是这个编码单元数。
如果有特殊字符编码的文本,需要精确统计字符数,可以使用codePointCount方法。在原来代码基础上添加以下测试代码。
Stringb="";System.out.println(temp.length()+b.length()+words.size());System.out.println(temp.length()+b.codePointCount(0,b.length())+words.size());分别输出
总之,它都能从侧面证明,起点小说统计字数大概率就是使用的length(),同时将连续数字,英文单词算作单个字符,同时英文输入法下的省略号等符号算作一个。同时中文输入法下的任意每个字符都计数。特殊字符长度需要看它的字符串中的Unicode代码单元的数目。
众所周知,在java里,涉及到钱的计算,必须使用BigDecimal,才能精确计算。
如果使用double,float会丢失精度。
假设一个VIP章节共有字数4689,普通会员每千字5分钱,那么订阅该章节需要多少钱?
使用double/float用两种方法进行计算
intwordCount=4689;intmonovalent=5;floatmoney=(wordCount*monovalent)/1000;System.out.println(money);doublemoney2=(wordCount/1000)*monovalent;System.out.println(money2);分别输出
23.020.0先乘后除只是丢失精度。先除后乘不仅仅丢失精度,丢失的精度经过乘法放大,其结果就相差越大了。
通过强转能得到正确结果,这里只是演示。
floatmoney=(float)(wordCount*monovalent)/1000;doublemoney2=((double)wordCount/1000)*monovalent;使用BigDecimal进行计算
System.out.println(BigDecimal.valueOf(wordCount).divide(BigDecimal.valueOf(1000),2,RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(monovalent)).doubleValue());System.out.println(BigDecimal.valueOf(wordCount).multiply(BigDecimal.valueOf(monovalent)).divide(BigDecimal.valueOf(1000),2,RoundingMode.HALF_UP).doubleValue());输出
23.4523.45这里使用bigdecimal有两点需要注意:
doublenumber=2.352356234234236D;System.out.println(number);System.out.println(newBigDecimal(number));//输出近似值System.out.println(BigDecimal.valueOf(number));System.out.println(newBigDecimal(String.valueOf(number)));输出
2.3523562342342362.3523562342342358988389605656266212463378906252.3523562342342362.352356234234236进行divide除法操作时,需设置RoundingMode,避免除不尽出现无限循环小数时,抛出异常Non-terminatingdecimalexpansion;noexactrepresentabledecimalresult.不管是先乘后除还是先除后乘,都能得到正确的结果。
同时上述的计算结果单位都是:分。23.445分,四舍五入为23.45分。
我们知道日常交易金额的最低单位为分,如果再精确就出现了厘。
对于厘的处理,起点的选择是直接抹去小数部份。不管23.445还是23.45都直接处理为23分钱。
同时起点不支持每章节直接使用人民币付费,而是先充值为起点币,1起点币=1分钱。所以订阅上述章节需支付23起点币。
这种方式,余额没有小数点。存储时可以直接使用int类型,充值扣费时也没有小数点精度的问题。
随便一搜,网上随处可见的,起点霸道合同,压榨作家写手的新闻。23.45抹零,23.99也抹零。
那么,奇了怪了,起点为什么会在付费金额这里直接抹零了呢?蚊子再小也是肉啊!
假设银行有如下10笔利息
0.000、0.001、0.002、0.003、0.0040.005、0.006、0.007、0.008、0.009如果采取传统的四舍五入方法的话,银行的盈利分别为
0,+0.001,+0.002,+0.003,+0.004-0.005,-0.004,-0.003,-0.002,-0.001这样相加,可以得知,银行亏损了0.005。
为了应对这种情况,银行家们开发了一种新的算法。故名银行家算法。
在java中,BigDecimal提供了一种ROUND_HALF_EVEN的舍入方式,即为银行家舍入法。
以下是代码演示:
/***只保留两位数的情况下,看第3位小数,如果第3位小数不为5,则直接四舍五入*如果第3位小数为5,如果第4位小数不为0,则统一进位*如果第4位小数为0或者叫没有第4位小数,则看第2位小数的奇偶*第2位小数为奇数舍去*第2位小数为偶数则进位*/System.out.println(newBigDecimal(String.valueOf("1.256")).setScale(2,BigDecimal.ROUND_HALF_EVEN));//1.26System.out.println(newBigDecimal(String.valueOf("1.254")).setScale(2,BigDecimal.ROUND_HALF_EVEN));//1.25System.out.println(newBigDecimal(String.valueOf("1.2551")).setScale(2,BigDecimal.ROUND_HALF_EVEN));//1.26System.out.println(newBigDecimal(String.valueOf("1.245")).setScale(2,BigDecimal.ROUND_HALF_EVEN));//1.24System.out.println(newBigDecimal(String.valueOf("1.255")).setScale(2,BigDecimal.ROUND_HALF_EVEN));//1.26输出
1.261.251.261.241.26对于起点为什么没有使用银行家算法,而是对小数部份直接抹零,我只能理解是钱太好赚了,它提供了一个平台,哪怕一只鸟飞过平台留下一根毛,起点也要分一半。这点零头就不计较了。
但我自己都不信,我可能懂那么一点技术,但我不懂资本家。
同时,谈到银行家算法处理利息,对于起点也有一个关于利息的疑问。
但这能证明起点不给利息合法吗?
你能想象吗?淘宝或者京东,购物时不支持三方支付,必须要先购买淘宝币或者京东币,然后再用币支付。同时,剩下的币不支持提现,也没利息?如果你不同意这种支付方式,就不能购物。
假如我充值了一百块钱,订阅了某个章节使用了几毛钱,然后索然无味,没再继续订阅后续章节,那账户里剩下的钱一直冻结在专用账户里没有用作它途产生非法的高额利润?就算没有,这笔钱躺在银行账户里本身也是有利息的,这部份利息肯定是没有向我本人发放的,这合法吗?
我想这才是起点在订阅时直接对小数点抹零的动机吧。背后的原因令人三级烫伤。
至于其它的,安卓端充值不能在苹果端消费(最早WEB端也不能),
订阅不是永久性的,已订阅商品可能需重复购买这些感觉都是小事了(给人的感觉就是,起点拿订阅打赏的一半的时候毫不手软,出问题的时候独善其身赶紧撇清)。