数学黑洞:卡普雷卡尔常数的php算法实现

首先看一篇文章:

 

  英国广播公司报道,6174乍看没什么奇特之处,但是,自从1949年以来,它一直令数学家、数字控抓狂、痴迷。

  不管你挑的四位数是什么,早早晚晚你都会遇到6174;而且,遇到6174就只能止步,否则面临的将是无休无止的无用功了。

  祝贺一下,现在你总算搞懂了卡普雷卡尔常数(Kaprekar's constant,又称卡布列克常数)。

  印度数学家卡普雷卡尔(1905-1986)最喜欢摆弄数字,正是他发现了6174的神奇魅力。

  自认数字理论控的卡普雷卡尔1949年在印度城市马德拉斯召开的一次数学会议上向世界宣布了自己的发现。

卡普雷卡尔就读于孟买大学,毕业后在孟买北部山区小镇带奥拉利(Devlali)当老师。

  印度数学家认为,卡普雷卡尔的发现很无聊,取笑一番,置之不理。不过,卡普雷卡尔是位高产作家,经常在大众科普刊物上发表文章。而且,他还常被请去参加各种会议、在学校巡回演说,介绍自己独特的方法和有趣的发现。

  逐渐,卡普雷卡尔在国内外知名度、受欢迎程度越来越高。到了1970年,美国畅销书作家、数学爱好者Martin Gardner在著名科普杂志《科学美国人》上发表文章介绍卡普雷卡尔。

  现在,卡普雷卡尔的名字在全世界数学爱好者——特别是数字控中——已经是如雷贯耳。

  日本大阪经济大学教授西山豊(Yutaka Nishiyama)认为,6174真是个“谜一样的数字”。在一篇网上文章中,西山教授解释说,他用电脑查证是否所有的四位数都能在有限步骤内得出6174。

  他的发现是,根据卡普雷卡尔的算法,所有四位数(只要四位数不重复)最多只需要7步运算就会得出6174。

  “如果7步还没有得出6174,那一定是你算错了。重来一遍吧。”

 

  把下面的代码保存为 index.php 存入服务器中,在浏览器中每刷新一次,程序会随机取出四位数进行卡普雷卡尔常数运算十步。

  (一)面向过程实现:

<?php
/**
  *  卡普雷卡尔常数的计算(6174的数字黑洞)
  *
  * 计算方法:任意四个不重复的一位数,它们组成的最大四位数减去它们组成的
  *         最小四位数所得的新四位重复前面的算法,最多七次就会得到6174。
  */
  
// 随机数产生四位原始数字的数组
$original = array( rand(1,9), rand(1,9), rand(1,9), rand(1,9));
$orig = implode( $original );
echo "<br>原数据:{$orig}<br>";

/**
  * $total[0]存放计算前的四位数
  * $total[1]存放计算后的四位数
  * $total[2]存放计算得到6174后的计算次数
  */
$total = array( 0, 0, 0 );
$tag = true;

/**
  * 整个计算就是一个 for 循环加 3 个函数完成的
  * 计算 10 次数据
  */
for( $i = 0; $i < 10; $i++)
{
    if( empty( $total[0] ) )
        $total[1] =$total[0] = calculation( $original );
    else
        $total[1] = calculation(  numToArr( $total[0] ) );

    // *****输出计算后的数据*****
    echo $total[1] . '<br>';
    
    if( $total[1] == 6174 && $tag)
    {
        $tag = false;
        $total[2] = $i;
    }
    $total[0] = $total[1];
}

echo '在第<strong style="color: red">' . $total[2] . '</strong>步使数据等于6174。<br>';

/**
  * 冒泡排序算法函数
  * ( php有原生的排序函数 sort() 升序和 rsort() 降序排序 )
  *
  * @param array $arr   要排序的数组;
  * @param bool  $order 为 true 升序,为 false 降序。
  * @return array
  */
  
function sortFunc($arr, $order = true)
{
    $val = 0;
    $count = count($arr) - 1;
    
    for($i = 0; $i < $count; $i++)
    {
        for($j = 0; $j < $count - $i; $j++)
        {
            if($order)
            {
                if($arr[$j] > $arr[$j + 1])
                {
                    $tag[1]++;
                    $val = $arr[$j + 1];
                    $arr[$j + 1] = $arr[$j];
                    $arr[$j] = $val;
                }
            }
            else
            {
                if($arr[$j] < $arr[$j + 1])
                {
                    $val = $arr[$j + 1];
                    $arr[$j + 1] = $arr[$j];
                    $arr[$j] = $val;
                }
            }
        }
    }
    return $arr;
}

/**
  * 卡普雷卡尔常数的计算函数
  *
  * 功能:任意四位数,排序后的最大数减去排序后的最小数。
  * @param array $arr 输入的任意四位数。
  * @return integer
  */
  
function calculation( $arr ){
    //①用冒泡排序法实现
    $big = sortFunc( $arr, false );
    $small = sortFunc( $arr);
    
    //②用 php 内置函数实现
    //$big = $small = $arr;
    //rsort( $big, SORT_NUMERIC );
    //sort( $small, SORT_NUMERIC );

    $valBig = ( int )implode( $big );
    $valSmall = ( int )implode( $small );

    $value = $valBig - $valSmall;
    return $value;
}

/**
  * 数字拆分成数组函数
  * 
  * @param integer $num 四位数如:8543
  * @return array       得到的数组如:array( 8, 5, 4, 3 )
* 如果用原生 php 函数是 str_split()
*/ function numToArr( $num ){ $arr = array(); $str = (string)$num; for( $i = 0; $i < strlen( $str ); $i++) { $arr[] = (int)substr( $str, $i, 1); } return $arr; }

 

  (二)用面向对象实现上面的面向过程:

<?php
/**
  *  卡普雷卡尔常数的计算(6174的数字黑洞)
  *
  * 计算方法:任意四个不重复的一位数,它们组成的最大四位数减去它们组成的
  *         最小四位数所得的新四位重复前面的算法,最多七次就会得到6174。
  */
   
class KaprekarConst{
    
    public $original = array();
    
    /**
      * $total[0]存放计算前的四位数
      * $total[1]存放计算后的四位数
      */
    public $total = array( 0, 0 );
    public $tag = true;
    
    /**
      * $val[0] 存放四位原始数据
      * $val[1] 存放循环计算 10 次的数组
      * $val[2] 存放计算到 6174 数据的次数
      */
    public $val = array();
    
    function __construct()
    {
        // 随机数产生四位原始数字的数组
        $this->original = array( rand(1,9), rand(1,9), rand(1,9), rand(1,9));
    }
    
    public function main()
    {
        $this->val[0] = implode( $this->original );
        
        /**
          * 整个计算就是一个 for 循环加 2 个方法完成的
          * 计算 10 次数据
          */
        for( $i = 0; $i < 10; $i++)
        {
            if( empty( $this->total[0] ) )
                $this->total[1] = $this->total[0] = $this->calculation( $this->original );
            else
                $this->total[1] = $this->calculation(  $this->numToArr( $this->total[0] ) );
    
            // *****输出计算后的数据*****
            $this->val[1][] = $this->total[1];
    
            if( $this->total[1] == 6174 && $this->tag)
            {
                $this->tag = false;
                $this->val[2] = $i;
            }
            $this->total[0] = $this->total[1];
        }
return $this->val; } /** * 卡普雷卡尔常数的计算方法 * * 功能:任意四位数,排序后的最大数减去排序后的最小数。 * @param array $arr 输入的任意四位数。 * @return integer */ public function calculation( $arr ){ $big = $small = $arr; rsort( $big, SORT_NUMERIC ); sort( $small, SORT_NUMERIC ); $valBig = ( int )implode( $big ); $valSmall = ( int )implode( $small ); $value = $valBig - $valSmall; return $value; } /** * 数字拆分成数组方法 * * @param integer $num 四位数如:8543 * @return array 得到的数组如:array( 8, 5, 4, 3 )
* 如果用原生 php 函数是 str_split()
*/ public function numToArr( $num ){ $arr = array(); $str = (string)$num; for( $i = 0; $i < strlen( $str ); $i++) { $arr[] = (int)substr( $str, $i, 1); } return $arr; } } $obj = new KaprekarConst; $val = $obj->main(); // 显示内容: echo '原数据:' . $val[0] . '<br>'; foreach( $val[1] as $value ) { echo $value . '<br>'; } echo '在第<strong style="color: red">' . $val[2] . '</strong>步使数据等于6174。';

 

程序执行后的效果:

 

posted @ 2019-12-18 19:33  孤舟残月浅笑嫣然  阅读(1188)  评论(0编辑  收藏  举报