一个赛事的小题目

nextPerfectSquare


这是一题摘自 codewars上的训练题。

Write a function name nextPerfectSquare / next_perfect_square that returns the first perfect square that is greater than its integer argument. A perfect square is a integer that is equal to some integer squared. For example 16 is a perfect square because 16=4*4.
Caution! The largest number test is close to Int64.MaxValue

题目很简单,就是给定一个数字,求出其后第一个平方数。负数因为没有平方数,其后第一个平方数为0。

examle
n		next prefect square
6		9
36		49
0		1
-5		1

题目很简单,因为很多人都会想到,将 n n n开平方,开方后的结果向下取整,其下数字再平方即为所求结果。我想信没有人会使用循环,从 n + 1 n+1 n+1开始,然后测试开方,得到整数即为下一平方数。

根据上文的叙述,差不多所有人都会考虑先开方的方式进行处理。那么程序也非常简单可以实现:

public static long NextPerfectSquare(long n)
{
   
	if(n<0) return 0;
	
	return (long)Math.Pow((long)Math.Sqrt(n+1),2);
}

严格来说没有问题的,Math.Sqrt(n+1)Math.Sqrt(n)+1的区别不大,都是解决若给字的数字是一个平方数时情况。这个问题解决起来也是三五分钟的事儿。运行也会通过测试,看起来天衣无缝,也几乎没有人注意到其中会存在的问题。

我的思路也是如此,先将 n n n开平方后,将其平方根取整叠1后的平方数即是要求的值。但是我看到其Caution时多了一重的想法——Math.Sqrt(long)时不一定能得到正确的结果!

在使用Math.Sqrt我们必须知道,该方法的入参是一个double数据类型,该类型是64bit空间,而long类型也是64bit空间。事实上每个计算机从业人员都知道double使用的是阶码表示法,而long使用的是被码表示法。换句话来说,同样64bit空间内,我们肯定用一个double表示出所有long,也就是说这步转换存在一个值不精确的问题。那么直接使用Maht.Sqrt肯定会存在较大的bug!

double阶码表示

double类型的有效数字只有52bits,而其余的空间是阶数与符号的存储。换句话来说,其0~51是表示有效位数,而52-62则是阶数表示位置,63表示的是符号。如果不考虑阶码的情况下,其值只能表示为 0 0 0 2 51 2^{51} 251!而long不考虑符号位时表示的能力却是 0 0 0 2 63 − 1 2^{63}-1 2631,即然存在这个差别,那也就是说Math.Sqrt入参为double的情况下,使用long计算未必是正确的。

当然,这里涉及到一个隐式计算,就是long可以隐式转换double。因为double虽然使用是仍是64bit的空间,但因为阶码的存在,它下可表示 2 10 2^{10} 210个小数点移位!也就是说可以左移小数点或右移小数点约 1024 / 10 ∗ 3 = 308 1024/1

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值