最近在公司一边自学一边写PHP程序,由于公司对程序的运行效率要求很高,而自己又是个新手,一开始就注意程序的效率很重要,这里就结合网上的一些资料,总结下php程序效率优化的一些策略:

1.在可以用file_get_contents替代file、fopen、feof、fgets等系列方法的情况下,尽量用file_get_contents,因为他的效率高得多!但是要注意file_get_contents在打开一个URL文件时候的PHP版本问题;(对这于这一点kimi不敢苟同,详细请查阅http://www.ccvita.com/index.php/163.html)

2.尽量的少进行文件操作,虽然PHP的文件操作效率也不低的;

3.优化Select SQL语句,在可能的情况下尽量少的进行Insert、Update操作(在update上,我被恶批过);

4.尽可能的使用PHP内部函数(但是我却为了找个PHP里面不存在的函数,浪费了本可以写出一个自定义函数的时间,经验问题啊!);

5.循环内部不要声明变量,尤其是大变量:对象(这好像不只是PHP里面要注意的问题吧?);

6.多维数组尽量不要循环嵌套赋值;

7.在可以用PHP内部字符串操作函数的情况下,不要用正则表达式;

8.foreach效率更高,尽量用foreach代替while和for循环;

9.用单引号替代双引号引用字符串;

10.“用i+=1代替i=i+1。符合c/c++的习惯,效率还高”;

11.对global变量,应该用完就unset()掉

class FtpGet {
    private $config;
    private $retry = 15;
    private $errors = array();
    
    function __construct($config = array()) {
        if (empty ( $config )) {
            $this->config = array (
                 ‘path_local’ => ‘/local/path’,
                 ‘path_remote’ => ‘/remote/path’,
                 ’server’ => ‘ftp.server.com’,
                 ‘username’ => ‘username’,
                 ‘password’ => ‘password’
            );
        } else {
            $this->config = $config;
        }
    }
    
    public function getFile($filename) {
        if (empty ( $filename ))
            return “”;
        $this->errors = array();
        $return_file = “”;
        $i = 0;
        while ( $i < $this->retry ) {
            try {
                //try to connect
                $conn = ftp_connect ( $this->config ['server'], 21 );
                if (! $conn) {
                    $this->errors['connect'] = “can not connect to the ftp server ” . $this->config ['server'];
                    sleep ( 30 );
                    $i ++;
                    continue;
                }
                
                //try to login
                $lr = ftp_login ( $conn, $this->config ['username'], $this->config ['password'] );
                if (! $lr) {
                    $this->errors['login'] =  “can not login to the ftp server ” . $this->config ['server'];
                    sleep ( 30 );
                    $i ++;
                    continue;
                }
                
                //check local path    
                if (! $this->checkPath ( $this->config ['path_local'] )) {
                    $this->errors['path'] =  “can not create local path {$this->config ['path_local']}, please chmod the dir to 777.”;
                    break;
                }
                
                //set to pasv mode
                if(!ftp_pasv ( $conn, true )){
                    $this->errors['pasv'] =  “can not set transfer mode to pasv.”;
                    break;
                }

                //get remote files list
                $fileList = ftp_nlist ( $conn, $this->config ['path_remote'] );
                if (count ( $fileList ) === 0) {
                    $this->errors['nofile'] =  “there is not files on the ftp server ” . $this->config ['server'];
                    sleep ( 600 );
                    $i ++;
                    continue;
                }
                
                //loop to check if matched the file
                foreach ( $fileList as $single_file ) {
                    if ((preg_match ( “/^(.*?)$filename\$/i”, $single_file )) && ftp_size ( $conn, $single_file ) > 0) {
                        $local_file = $this->config ['path_local'] . “/” . basename ( $filename );
                        $rs = ftp_get ( $conn, $local_file, $single_file, FTP_BINARY );
                        if ($rs) {
                            $return_file = $single_file;
                        } else {
                            $this->errors['nofile'] = “can not get the file ” . $single_file;
                        }
                        break;
                    }
                }
                
                //close ftp connection
                $this->errors['close'] = ftp_close ( $conn );
            
            } catch ( Exception $e ) {
                $this->errors['exception'] = “found error: {$e->getMessage()}\n”;
                sleep(5);
            }
            if (! empty ( $return_file )) {
                break;
            }
            
            $i ++;
        }
        
        if (empty($return_file) && count($this->errors) > 0) {
            $title = “[Error] Could not get file {$filename} from ftp server {$this->config['server']}”;
            $message = implode(”\n”, $this->errors);
            $this->sendMail ( $title, $message );
        }
        return $return_file;
    }
    private function checkPath($Path) {
        if (! is_dir ( $Path ) || ! file_exists ( $Path )) {
            if (mkdir ( $Path, 0777 )) {
                return 1;
            } else {
                return 0;
            }
        } else {
            return 1;
        }
    }
   
    private function sendMail($title, $msg) {
        $boundary = uniqid ();
        $mail_header = “From: abc@from.com\n”;
        $mail_header .= “Content-type: multipart/related; boundary=\”{$boundary}\”\n”;
       
        $mail_body = “\n–{$boundary}\n”;
        $mail_body .= “Content-type: text/plain; charset=\”iso-8859-1\” \n”;
        $mail_body .= “Content-transfer-encoding: 7bit \n\n”;
        $mail_body .= “This is a auto mail from process download file from ftp server.\n”;
        $mail_body .= “{$msg}\n\n”;
       
        $mail_body .= “–{$boundary}–\n”;
       
        $mail_to = “haha@email.com”;
        if (mail ( $mail_to, $title, $mail_body, $mail_header )) {
            echo “Send alert email successfully ! \n”;
        }
    }
}

以前在找了 MIME 的一些资料,只显示 doc、xls 等 office 2002 之类的格式有 MIME

如 .doc MIME 就设置成 application/msword 就可以了。在网页里面docx 文件是没问题,但是下载下来了之后就变成doc格式了,虽然打开是没问题,但总感觉有点不爽。今天我又搜索了一些。搜到了:

原文网址

.dotx,application/vnd.openxmlformats-officedocument.wordprocessingml.template
.docx,application/vnd.openxmlformats-officedocument.wordprocessingml.document
.xlsx,application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
.pptx,application/vnd.openxmlformats-officedocument.presentationml.presentation

.doc,application/msword

.dot,application/msword

.xls,application/vnd.ms-excel

文件的大小函数为:filesize()
文件是否存在的函数为:file_exits();
但是这两个函数只针对本地

那么:远程文件是否存在,远程文件大小 如何得知呢?

搜索了一下,有人居然说,把远程文件下载过来再判断这个远程文件的大小,这是什么歪理。

庆幸大部分人还是清醒的,一般应该使用判断header反馈的信息进行判断。

php中如何获得header信息呢? php的函数真多,这个也不例外

1.最简单的获取远程文件大小办法

$a_array = get_headers(url,true);
url就是网址了,至于第二个参数

就可以得到类似下面的这个数组

Array
(
[0] => HTTP/1.1 200 OK
[Date] => Sat, 29 May 2004 12:28:14 GMT
[Server] => Apache/1.3.27 (Unix) (Red-Hat/Linux)
[Last-Modified] => Wed, 08 Jan 2003 23:11:55 GMT
[ETag] => “3f80f-1b6-3e1cb03b”
[Accept-Ranges] => bytes
[Content-Length] => 438
[Connection] => close
[Content-Type] => text/html
)

所以,你可以很舒服的拿到远程文件的大小
$file_sizeofurl = a_array['Content-Length'];
2.用curl获取远程文件大小
如果服务器禁止get_headers 怎么办?
换一种办法,用curl
我总觉得curl就像一个虚拟的用户,什么都能模仿

下面直接给出一个老外的函数
请注意
echo '
head-->'.$head.'<----end
‘;

这句是我加的,为了知道header里面到底包含了什么东西
function remote_filesize($uri,$user='',$pw='')
{
// start output buffering
ob_start();
// initialize curl with given uri
$ch = curl_init($uri);
// make sure we get the header
curl_setopt($ch, CURLOPT_HEADER, 1);
// make it a http HEAD request
curl_setopt($ch, CURLOPT_NOBODY, 1);
// if auth is needed, do it here
if (!empty($user) && !empty($pw))
{
$headers = array('Authorization: Basic ' . base64_encode($user.':'.$pw));
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
}
$okay = curl_exec($ch);
curl_close($ch);
// get the output buffer
$head = ob_get_contents();
// clean the output buffer and return to previous
// buffer settings
ob_end_clean();

echo ‘
head–>’.$head.’<—-end
‘;

// gets you the numeric value from the Content-Length
// field in the http header
$regex = ‘/Content-Length:s([0-9].+?)s/’;
$count = preg_match($regex, $head, $matches);

// if there was a Content-Length field, its value
// will now be in $matches[1]
if (isset($matches[1]))
{
$size = $matches[1];
}
else
{
$size = ‘unknown’;
}
//$last=round($size/(1024*1024),3);
//return $last.’ MB’;
return $size;
}

3.fsock获取远程文件大小的办法
先给函数
function getFileSize($url){
$url = parse_url($url);
if($fp = @fsockopen($url['host'],empty($url['port'])?80:$url['port'],$error)){
fputs($fp,”GET “.(empty($url['path'])?’/':$url['path']).” HTTP/1.1rn”);
fputs($fp,”Host:$url[host]rnrn”);
while(!feof($fp)){
$tmp = fgets($fp);
if(trim($tmp) == ”){
break;
}else if(preg_match(’/Content-Length:(.*)/si’,$tmp,$arr)){
return trim($arr[1]);
}
}
return null;
}else{
return null;
}
}

哪个获取远程文件大小最快?
针对同一个url进行测试,curl > fsock > getheader
针对不同url测试,结果还是 curl > fsock > getheader
当然也许这个测试是不准确的,但getheader函数是明显要慢一些的

考虑到curl模块没有fsock那么普及,所以我自己还是用后面一个

速度上的差别大约是 curl比fsock快0.2秒,fsock比getheader快0.2秒。

远程文件的大小拿来干嘛用?
好像某些人用来分块下载文件
我是拿来判断远程文件是否更新(虽然不准),其他人有什么好办法不?给我留言吧

oracle改字段名

alter table tbname rename column internaltype to intervaltype;

oracle锁表

如果一个用户正在更新某张表但没有提交,另一个用户就不能对同一张表使用update命令操作

        SimpleDateFormat sdfParse = new SimpleDateFormat(”MMMMM dd, yyyy”, Locale.ENGLISH);
        SimpleDateFormat sdfFormat = new SimpleDateFormat(”yyyy-MM-dd”);
        SimpleDateFormat comFormat = new SimpleDateFormat(”yyyyMMdd”);
       
        long start = System.currentTimeMillis();
        Config.init(”app.properties”);
       
        //prepare db
        StringBuilder sql = null;
        Statement st = null;
        Connection conn = null;
        try{
            Class.forName(Config.get(”DB_DRIVER”)).newInstance();
            conn = DriverManager.getConnection(Config.get(”DB_DSN”), Config.get(”DB_USERNAME”), Config.get(”DB_PASSWORD”));
            st = conn.createStatement();
        }catch(InstantiationException e){
            e.printStackTrace();
        }catch(ClassNotFoundException e){
            e.printStackTrace();
        }catch(SQLException e){
            e.printStackTrace();
        }catch(Exception e){
            e.printStackTrace();
        }
       
        //change timezone
        Calendar calendar = GregorianCalendar.getInstance();
        int millisDiff = TimeZone.getTimeZone(Config.get(”TZ_DATA”)).getRawOffset() - TimeZone.getDefault().getRawOffset();
        calendar.setTimeInMillis(calendar.getTimeInMillis()+millisDiff);
       
        Calendar calYesterday = (Calendar)calendar.clone();
        calYesterday.add(Calendar.DAY_OF_YEAR, -1);

        Calendar calLastWeekDay = (Calendar)calYesterday.clone();
        calLastWeekDay.add(Calendar.DAY_OF_YEAR, - Integer.parseInt(Config.get(”OFFSET_DAYS”)));
       
        System.out.println(”From: “+sdfFormat.format(calLastWeekDay.getTime()));
        System.out.println(”To: “+sdfFormat.format(calYesterday.getTime()));
       
        int i = 0, m = 0;
        HashMap<String, HashMap> data = new HashMap<String, HashMap>();
        HashMap<String, String> item = null;//new HashMap<String, String>()
        String u = Config.get(”START_URL”);
        WebClient client = new WebClient();
        client.setCssEnabled(false);
        client.setJavaScriptEnabled(false);
        client.setRedirectEnabled(true);
        client.setThrowExceptionOnScriptError(false);
        client.setThrowExceptionOnFailingStatusCode(false);
        client.setTimeout(0);
        try {
            //login
            HtmlPage p = (HtmlPage) client.getPage(u);
            HtmlForm form = (HtmlForm) p.getFormByName(”sign_in”);

            HtmlInput email = (HtmlInput) form.getInputByName(”email”);
            HtmlInput pass = (HtmlInput) form.getInputByName(”password”);
            HtmlInput submit = (HtmlInput) form.getInputByValue(”サインイン”);
            email.setValueAttribute(Config.get(”USERNAME”));
            pass.setValueAttribute(Config.get(”PASSWORD”));

            HtmlPage pr = (HtmlPage) submit.click();
           
            //go to report page
            HtmlPage er = client
                    .getPage(”https://the.report.page”);

            form = er.getFormByName(”htmlReport”);
           
            //set options
            form.getInputByValue(”exact”).setChecked(true);
           
            form.getSelectByName(”startMonth”).setSelectedAttribute(String.valueOf(calLastWeekDay.get(Calendar.MONTH)), true);
            form.getSelectByName(”startDay”).setSelectedAttribute(String.valueOf(calLastWeekDay.get(Calendar.DAY_OF_MONTH)), true);
            form.getSelectByName(”startYear”).setSelectedAttribute(String.valueOf(calLastWeekDay.get(Calendar.YEAR)), true);
           
            form.getSelectByName(”endMonth”).setSelectedAttribute(String.valueOf(calYesterday.get(Calendar.MONTH)), true);
            form.getSelectByName(”endDay”).setSelectedAttribute(String.valueOf(calYesterday.get(Calendar.DAY_OF_MONTH)), true);
            form.getSelectByName(”endYear”).setSelectedAttribute(String.valueOf(calYesterday.get(Calendar.YEAR)), true);
           
            HtmlInput gt = form.getInputByValue(”レポートのダウンロード(CSV形式)”);
            InputStream in = null;
           
            //retry if not available
            int retry = 0;
            while(in == null && retry < 50){
                in = gt.click().getWebResponse().getContentAsStream();
                if(in == null){
                    System.out.println(”Data not available! wait for 1 minute…”);
                    Thread.sleep(60000);
                }
                retry++;
            }

            //parse report
            BufferedReader br = new BufferedReader(new InputStreamReader(in, “UTF-8″));
            String line = null, key = null;
            String[] cols = null;
            HashMap<String, String> tmp = null;
            br.readLine();

            while ((line = br.readLine()) != null) {
                i++;
                item = new HashMap<String, String>();
                cols = StringUtils.splitPreserveAllTokens(line, “\t”);//.split(”\t”);
                System.out.println(”line”+i+” = “+cols.length);
                if(cols.length<11 || i<2){
                    for(int k=0; k<cols.length; k++){
                        System.out.println(”cols["+k+"]=”+cols[k]);
                    }
                    continue;
                }

                String settleDate = sdfFormat.format(sdfParse.parse(cols[5]));
                key = cols[2].trim()+settleDate;
                item.put(”OUTGOINGID”, cols[2].trim());
                item.put(”SETTLEDATE”, settleDate);
                if(data.containsKey(key)){
                    tmp = data.get(key);
                    item.put(”ORDERCOUNT”, String.valueOf(Integer.parseInt(tmp.get(”ORDERCOUNT”)) + Integer.parseInt(cols[8].replaceAll(”,”, “”))));
                    item.put(”ORDERAMOUNT”, String.valueOf(Double.parseDouble(tmp.get(”ORDERAMOUNT”)) + Double.parseDouble(cols[9].replace(”¥”, “”).replaceAll(”,”, “”))));
                    item.put(”REVENUE”, String.valueOf(Double.parseDouble(tmp.get(”REVENUE”)) + Double.parseDouble(cols[10].replace(”¥”, “”).replaceAll(”,”, “”))));
                }else{
                    item.put(”ORDERCOUNT”, String.valueOf(Integer.parseInt(cols[8].replaceAll(”,”, “”))));
                    item.put(”ORDERAMOUNT”, String.valueOf(Double.parseDouble(cols[9].replace(”¥”, “”).replaceAll(”,”, “”))));
                    item.put(”REVENUE”, String.valueOf(Double.parseDouble(cols[10].replace(”¥”, “”).replaceAll(”,”, “”))));
                }
                data.put(key, item);
            }
           
            br.close();
            in.close();

        } catch (Exception e) {
            e.printStackTrace();
        }
       
       
        //save report
        for(Entry<String, HashMap> entry:data.entrySet()){
            item = entry.getValue();
            sql = new StringBuilder();
            sql.append(”select OUTGOINGID, SETTLEDATE, sum(REVENUE) as REVENUE from “);
            sql.append(Config.get(”TBL_CPA”));
            sql.append(” where OUTGOINGID=’”);
            sql.append(item.get(”OUTGOINGID”));
            sql.append(”‘ and to_char(SETTLEDATE, ‘yyyy-mm-dd’)=’”);
            sql.append(item.get(”SETTLEDATE”));
            sql.append(”‘ group by OUTGOINGID, SETTLEDATE”);
           
            try{
                st.execute(sql.toString());
   
                double oldRev = 0;
                if(st.getResultSet().next()){
                    oldRev = st.getResultSet().getDouble(”REVENUE”);
                }
                System.out.println(”oldRev=”+oldRev);
                double newRev = Double.parseDouble(item.get(”REVENUE”));
                double varRev = newRev-oldRev;
                if (varRev != 0){
                    System.out.println(”newRev=”+newRev);
                    sql = new StringBuilder();
                    sql.append(”insert into “);
                    sql.append(Config.get(”TBL_CPA”));
                    sql.append(”(WEBSITE, OUTGOINGID, SETTLEDATE, ORDERAMOUNT, ORDERCOUNT, REVENUE, LOADDATE)”);
                    sql.append(”values(1, ‘”);
                    sql.append(item.get(”OUTGOINGID”));
                    sql.append(”‘, to_date(’”);
                    sql.append(item.get(”SETTLEDATE”));
                    sql.append(”‘, ‘yyyy-mm-dd’), “);
                    sql.append(item.get(”ORDERAMOUNT”));
                    sql.append(”,”);
                    sql.append(item.get(”ORDERCOUNT”));
                    sql.append(”,”);
                   
                    sql.append(String.valueOf(varRev));
                    sql.append(”, to_date(’”);
                    sql.append(sdfFormat.format(calYesterday.getTime()));//
                    sql.append(”‘, ‘yyyy-mm-dd’))”);
                   
                    st.execute(sql.toString());
                   
                    m++;
                }else{
                    System.out.println(”Found no change: “+item.get(”OUTGOINGID”)+” : “+item.get(”SETTLEDATE”));
                }
            }catch(SQLException e){
                e.printStackTrace();
            }
        }
        System.out.println(”total=”+i+”; matched=”+m);
       
        //write log
        sql = new StringBuilder();
        sql.append(”begin user.log_proceduce(’the_site’, ‘cpa_”);
        sql.append(comFormat.format(calYesterday.getTime()));
        sql.append(”.dat’,”);
        sql.append(m);
        sql.append(”,0, null, ‘revenue’); end;”);
       
        try{
            st.execute(sql.toString());
        }catch(SQLException e){
            e.printStackTrace();
        }
       
        client = null;
        long cost = (System.currentTimeMillis()-start)/1000;
        System.out.println(”cost time: “+String.valueOf(cost)+” secs.”);

什么是云计算

  云理论是实现概念的定性值与数字的定量值之间自然转换的有力工具。

 

  本文在云理论的基础上,提出了实现概念计算(也叫简化计算)的云计算方法。概述了云模型与不确定推理;给出了计算的逻辑描述,将计算过程抽象成 为推理过程;运用机器学习的方法,给出了计算云化的过程,并且采用不确定推理的方法,给出了云的计算过程;简单阐述了云化计算的系统实现。

 

  随着网络的日益普及,“网络存储”这样的服务也日益深入人心,有了众多的使用者,网络服务业方面的开发商自然不会错过这个大市场。几天前,微软 推出了Windows Live SkyDrive,并已经在互联网上全面进行测试,虽然容量仅仅为500MB,但是毕竟是免费的,使用的人数量极为可观。而谷歌也不是等闲之 辈,SkyDrive刚刚登场就推出了自己的超大容量网络存储方案,不过收取的费用上还需要商榷。另外,苹果公司开发的.Mac平台也瞄准了“网络存储” 这块大蛋糕,随时准备加入这场 “战争”。

 

  近日,arstechnica等国外各大网站发表了一篇名为《Google, Microsoft and Apple building online storage havens: you win》的文章,引起了全球范围内网友的热烈讨论,微软、谷歌、苹果的“粉丝”在各大论坛议论纷纷,强烈支持各自的“阵营”,一时间硝烟四起,网络存储三 强鼎立的局面已经日渐明显。

 

  微软公司的SkyDrive走的是纯免费路线,不过不排除这只是微软公司的“鱼饵”,毕竟天上还是不会掉馅饼的。谷歌公司则直接与美元挂钩,要 想用我的服务,当然可以,而且非常欢迎,但是容量的大小是要用美元来衡量的。从2.8GB升级到2.8GB+6GB也许我们都还可以接受,但是500美元 直接买下 250GB的空间则有些奢侈了,而且仅局限于谷歌本身的服务拓展性也太小了。苹果公司的.Mac平台之前就已经有网络存储的服务了,不过现在容量却已经从 当时极不起眼的1GB升级到了10GB,同样是99美元的.Mac平台使用年费,加量不加价是感觉还是不错的。

 

  竞争必然会引起降价和服务质量的提升,相信这也是我们普通用户希望看到的,而网络存储全面普及的时代也将来临,希望从“云计算”(Cloud computing)的“云存储”发展起来的网络存储能够带给我们更多的惊喜,正如目前的IM即时通讯软件那样百花齐放。
Read the rest of this entry »

陈省身
(庆祝自然科学基金制设立15周年和国家自然科学基金委员会成立10周年的讲演)

    张存浩先生要我讲点数学,这么短的时间,而数学这么大,只好举几个要点谈谈。

    数学是什么?数学是根据某些假设,用逻辑的推理得到结论,因为用这么简单的方法,所以数学是一门坚固的科学,它得到的结论是很有效的。这样的结论自然对学问的各方面都很有应用,不过有一点很奇怪的,就是这种应用的范围非常大。

    最初你用几个数或画几个图就得到的一些结论,而由此引起的发展却常常令人难以想象。在这个发展过程中,我认为不仅在数学上最重要,而且在人类文化史上也非常突出的就是Euclid在《几何原本》。这是第一本系统性的书,主要的目的是研究空间的性质。这些性质都可以从很简单的公理用逻辑的推理得到。这是一本关于整个数学的书,不仅仅限于几何学。例如,Euclid书上首先证明素数的个数是无穷的,这便是一个算术的结论。随着推理的复杂化,便有许多“深刻”的定理,需要很长的证明。例如 ,有些解析数论定理的证明,便需几十条引理。

    最初,用简单的方法证明几个结果,大家很欣赏,也很重要。后来方法发展了,便产生很复杂的推理,有些定理需要几十页才能证明。现在有的结果的证明甚至上百页,上千页。看到这么复杂的证明,我们固然惊叹某些数学家高超的技巧和深厚的功力,但心中难免产生一些疑问,甚或有些无所适从的感觉。所以我想,日后数学的重要进展,在于引进观念,使问题简化。
先讲讲有限单群的问题。

1.有限单群

    我们知道,数学的发展中有一个基本观念——群。群也是数学之中各方面的最基本的观念。怎样研究群的结构呢?最简单的方法是讨论它的子群,再由小的群的结构慢慢构造大一些的群。群中最重要的一种群是有限群,而有限群是一个难极了的题目,需要有特别的方法,特别的观念去研究。

    命G为群,g∈G为一子群,如对任何g∈G-1g H g ∈H,则称H为正规的(nomal). 正规子群存在,可使G的研究变为子群H及商群G/H的研究。这样就有一个很自然的问题,有哪些有限的单群(*** group).单群除了它自己和单位元(identity)之外,没有其他的非平凡的正规子群(normalsubgroup). 数学上称其为简单群,其实一点也不简单。

    有限群论的一个深刻的定理是Fei-Thompson定理:非交换单群的阶(数)(即群中元素的个数)是偶数。更不寻常的是除了某些大类(素数阶循环群Zp,交错群An(n>=5), Lie型单群)外,后来发现了26个零零碎碎的有限单群(散在单群,离散单群), 现在知道,最大的散在单群的阶是241×320×59×76×112×133×17×19×23×29×31×41×47×59×71 =808,017…=1054

    这是很大的单群,由B。Fisher 和 R。L.Griess两位数学家所发现,数学家称它为魔群(怪物,Monster).

    单群的权威数学家D.Gorenstein相信有限单群都在这里了,这当然是数学上一个很好的结果。把单群都确定了,就像化学家把元素都确定了,物理学家把核子的结构都确定了一样。可这里有个缺点,Gorenstein并未将证明定出来。他讲若将证明写出来至少有1000页,而1000页的证明无论如何很容易有错误。可是Gorenstein又说,不要紧,若有错误,这个错误一定可以补救。你相信不相信?数学界有些人怀疑这样的证明是否必要。现在计算机的出现,许多问题可以验证到很大的数,是否还需要严格的证明,已变成数学上一个有争论的问题。这个争论看来一时无法解决。段学复先生是我的老朋友,是有限群论的专家,也许我们可以问一下他的意见。我个人觉得这个问题很难回答。不过数学家有个自由,当你不能做或不喜欢做一个问题时,你完全不必投入,你只需做一些你能做或喜欢做的问题。

2.四色问题

     把地图着色,使得邻国有不同的颜色,需要几种颜色?经验告诉我们,四色够了。但是严格的证明极难。这就是有各的四色问题。

    地图不一定在球面上,也可在亏格高的的曲面上(一个亏格高为g的曲面在拓扑上讲是球面加g个把手;亏格为1的曲面可设想为环面)。可惊奇的是,这个着色问题,对于g>=1的曲面完全解决了。可以证明:有整数χ(g),满足条件:在亏格为g的曲面上任何地图都可用χ(g)种颜色着色,使邻国有不同颜色,且有地图至少需要χ(g) 种颜色。这个数在g>=1时可以完全确定。我们知道χ(1)=7,即环面上的地图可用七色着色,四色不够。

    令人费解的是,证明地球上四色定理,困难多了。现有的证明,需要计算机的帮助,与传统的证明不同。而我们觉得最简单的情况,即我们住的地球球面上的着色问题反而特别复杂。把扩充的问题解决了,得到了很有意思的结论。但是回到基本问题,反而更难。

    这种现象不止这一个,还有很多,一个例子是所谓的低维拓扑,即推广的问题更简单,而本身核心的问题反而不易克服,这确是数学神秘性的一面。

3.椭圆曲线

    最近的数学进展,最受人注意的结果就是Fermat大定理的证明。Fermat大定理说:方程式xn + yn=zn ,n>2没有非平凡的整数解(即xyz<>0). 这个传说了300年的结果的证明,最近由Princeton大学的教授Andrew J.Wiles(英国数学家)给出。但证明中缺一段,是由他的学生Richard Tarlor补充的。因此,Fermat 定理现在已经有了一个完全的证明。整个文章发表在最近一期的“Annals of Mathematics”(Prinston大学杂志,1996,第一期)整个一期登的是Wiles与Taylor的论文,证明Fermat定理(Wiles为此同Robert Langlands 获得了1996年的Wolf奖与National Academy Science Award in Mathematics).

    有意思的是,证明这个定理的关键是椭圆曲线。这是代数数论的一个分支。有以下一则故事。英国的大数学家G.H.Hardy(1877-1947)有一天去医院探望他的朋友,印度天才数学家S.A.Ramanujan(1887-1920).Hardy 的汽车号是1729。他向Ramanujan说,这个数目没有意思。Ramanujan说,不然,这是可以用两种不同方法写为2个立方之和的最小的数,如1729=13+123=93+103这结果可用椭圆曲线论来证明。

    我们知道,要找一个一般方程的解不容易的,而要找一个系数为整数的多项式方程P(x,y) = 0(传统上叫Diophantine方程)的整数解更困难。因为普通的解不会是整数,这是数论中的一个主要问题。

    需要说明的,在Wiles 完成这个证明之前,我有一位在Berkley的朋友Kenneth A.Ribet ,他有重要的贡献。他证明了一日本数学家Yutaka Taniyama的某一个关于椭圆曲线的假设包含Fermat定理。于是可将Fermat 定理变为一个关于椭圆曲线的定理。Wiles根据Ribet的结果又继续经过了许多步骤,以至达到最后的证明。即在复平面内得到曲线。由复变函数论知道,复平面内的曲线就成为一个Riemann曲面。Riemann曲面为定向曲面,它可以是球,也可以是球加上好多把手。其中有一个最简单的情形,就是一个球加上一个把手,即一个环面。环面是个群,且为可交换群。

    所谓椭圆曲线,就是把这个曲线看成复平面内亏格(genus)等于1的复曲线。亏格等于1的曲线有一个非常深刻而巧妙的性质。即它上面的点有一个可交换群的构造。两个点可以加起来,且有群的性质。这是很重要的性质。椭圆曲线与椭圆无关。原因是,若所有曲线的亏格大于1,相当于Riemann曲面有一个Poincare度量,它的曲率等于1,所有曲面若其曲率等于—1,则叫做双曲的。亏格等于1的叫椭圆。亏格等于0的叫抛物线。椭圆曲线的研究是数论中非常重要,非常有意思的方面。最近一期的科学杂志(Science),有位先生写了一篇关于椭圆曲线的文章。椭圆曲线在电报的密码上有应用。而中国也有很多人在做代数几何与代数数论方面的工作。最近在黄山有一个国际性的,题为“代数几何与代数数论”的会议,由冯克勤先生主持。

    从这个定理我们应认识到:高深的数学是必要的。Fermat定理的结论虽然简单,但它蕴藏着许多数学的关系,远远超出结论中的数学观念。这些关系日新月异,十分神妙,学问之奥,令人拜赏。

    我相信,Fermat定理不能用初等方法证明,这种努力是徒劳的。数学是一个整体,一定要吸取几千年所有的进步。

4.拓扑与量子场论

    1995年初的一天晚上,我在家看晚间电视新闻。突然,我听到自己的名字,大吃一惊。原来加利福尼亚发一种彩票,头彩300万美元,若无人中彩的话,可以积累到下一次抽彩。我从前的一个学生,名Robert Uomini, 中了头彩美金2200万元。他曾选过我的本科课,当时还对微分几何很有兴趣。他很念旧,以100万美元捐赠加州大学,设立“陈省身讲座”。学校决定,以此讲座邀请名学者为访问教授。第一位应邀的为英国数学家Sir Michael Atiyah. 他到中国不止一次。他是英国影响最大的数学家,剑桥大学三一学院的院长,则卸任的英国皇家协会会长。Atiyah很会讲学,也很博学,他的报告有很大的吸引力。他作了八讲,讲题是“拓扑与量子场论”。

    这是当前一个热门的课题,把高深的数学和物理联系起来了,导出了深刻的结果。现在拓扑在物理上有非常重要的应用,这跟杨振宁的Yang-Mills场方程有很密切的关系。

    杨先生喜欢说,你们数学家写的东西,我们学物理的人看不懂,等于另外一种文字。我想我们搞数学的人有责任把我们的结果,写成不是本行的人也至少知道你讲的是怎么一回事。

    物理学,量子力学,尤其是量子场论与数学的关系其实并不复杂。说到数学的应用,讲一下矢量空间,Euclid空间就是一个矢量空间。再进一步,多个矢量空间构成一个拓扑空间,这就是所谓的矢量丛,即一束这样的空间。这样的空间有一些简单的性质。比如说,局部来讲,这种矢量空间是一个chart,是一个集,可用坐标来表示。结果发现矢量丛这种空间在物理上很有用。物理学的一个基本观念是“场”。最简单的场是电磁场,尤为近代生活的一部分。电磁场的“势”适合Maxwell方程。Hermann Weyl第一个看出这个势不是一个确定的函数。它可以变化。这在物理上叫做规范(gauge, 不完全确定的,可以变化的),这就是物理上规范场论的第一个情形。

    物理上有4种场:电磁场,引力场,强作用场和弱作用场。现在知道,这些场都是规范场。即数学系上是一束矢量空间,用一个线性群来缝住的。电磁场的重要推广,是Yang-Mills的规范场论。杨先生的伟大贡献就是在SU(2)(special unitary group in two variables)情形下得到物理意义明确的规范场,即同位旋(isospin)规范场,这种将数学现象给以物理的解释,是件了不起的工作,因为以往的Maxwell场论是一个可交换的群。现在变为在SU(2),群是不能交换的。而实际上,物理中找到了这样的场,这是科学上一个伟大的发展。数学家可以自豪的是,物理学家所需的几何观念和工具,在数学上已经发展了。

    杨先生之所以有这么大的成就,其中一个很重要的,很了不起的原因是除了物理的感觉以外,他有很坚实的数学基础。他能够在这大堆复杂的方程中看出某些规律,它们具有某种基本的数学性质。Yang-Mills方程的数学基础是纤维丛。这种观念Dirac就曾有过。Dirac的一篇基本论文中就讲到这种数学。但Dirac没有数学的工具。所以他在讲这种观念时,不但数学家不懂,就连物理学家也不懂。不过,其中有一个到现在还未解决的物理含义,即有否磁单极(magnetic monople)。可能会有。就是说,有否这样的场,它的曲率不等于0(曲率是度量场的复杂性的)?物理上要是发现了这种场,会是件不得了的事实。这些观念的数学不简单。

    Yang-Mills方程反过来影响到拓扑。现在的基础数学中,所谓低维拓扑(二维,三维,四维)非常受人注意。因为物理空间是四维空间。而四维空间有许多奇妙的性质。我们知道代数几何,曲线论,复变函数论等许多基础数学理论是二维拓扑。而现在必到四维,四维有spinor理论,有quantum结构。四维与物理更接近。它的结构是Lorentz结构,而不是Riemann结构。这方面有很多工作可做。根据Yang-Mills方程,对于四维拓扑,Atiyah的学生英国数学家Simon Donaldson有很重要的贡献。其中有一个结果就是利用Yang-Mills方程证明四维Euclid空间R4有无数微分结构与其标准结构不同。这一结果最近又由Seiberg-Witten的新方程大大的简化了。这是最近拓扑在微分几何,理论物理应用方面最引人注意的进展。

    二维流形的发展有一段光荣的历史,牵涉到许多深刻的数学,可以断言,三维,四维流形将更为丰富和神妙。

5.球装问题(Sphere Packing)

    如何把一定的空间装得最紧,显然是一个实际而重要的问题。项武义教授最近在这方面做了很重要的工作。这里先介绍一个有关的问题:围着一个球,可以放几个同样大小的球?我们不妨假定球的半径为一,即单位球。在平面情形,绕一单位圆我们显然可以放6个单位圆。而在三维空间的情况则更为复杂。如果把单位球绕单位球相切,不难证明,12个球是放得进的。这时虽然还剩下许多空间,但不可能放进第13个球。要证明这一结论并不容易。当年Newton与Gregory有个讨论。Newton 说第13个球装不进,Gregory说也许可以。这个争论长期悬而未决。一直到1953年,K.Schutte和B.L.van der Waerden才给了一个证明。这个证明是很复杂的。

    一个更自然的问题是怎样把一个立方体空间用大小相同的球装得最紧。衡量装得是否紧凑的尺度是密度(density),即所装的球的总的体积和立方体空间的体积的比例。

    Kepler于1611年提出了一个猜想:他认为立方体的球装的密度不会大于π/(181/2).

    项武义说他证明了这个猜想。可是有人(Gabor Fejes Toth)认为他的证明不完全,甚至有人(Thomas L.Hales)说是错误的。”Mathematical Intelligencer”这个杂志上(1995年),有关于这一问题的讨论,项武义有个答复。Toth 是匈牙利数学家,三代人搞同一个课题。匈牙利数学很发达,在首都布达佩斯有个200多人的几何研究所。我不知道几何中是否有这么多重要的问题需要这么多人去做。最年轻的Toth在“Mathematics Reviews”中有篇关于项的文章的评论。他说项的文章有些定理没有详细的证明。天下的事情就是这样。做重要工作有争议的时候,便产生一些有趣的现象。不过他觉得项的意思是对的。不但项的意思是对的,甚至表示这个意思他从前也有。最近项武义抒他认为没有的证明都有写出来了。

    最主要的,我要跟大家说的是立体几何在数学中是很重要而因难的部分。即使平面几何也可能很难。到了立体时,则更为复杂。近年来对碳60(C60)的研究显示了几何在化学中的应用。多面体图形的几何性质对固态物理也有重大的作用。。球装不过是立体几何的一个问题。立体几何是大有前途的。

6.Finsler几何

    最近经我鼓励,Finsler几何有重大发展,作简要报告如下:

    在(x,y)平面上设积分s = ∫ab F(x,y,dy/dx)dx其中y是x的未知函数。求这个积分的极小值,就是第一个变分学的问题。称积分s为弧长,把观念几何化,即得Finsler几何。

    Gauss看出,在特别情形:

    F2 =E(x,y) + 2F(x,y) y’ +G(x,y)y’2 ,y’=dy/dx其中E,F,G为x,y的函数,几何性质特别简单。1854年,Riemann的讲演讨论了整个情形,创立了Riemann-Finsler几何。百余年来,Riemann几何在物理中有重要的应用,而整体Riemann几何的发展更是近代数学的核心部分。

    Riemann的几何基础包含Finsler几何。我们最近几年的工作,把Riemann几何的发展,局部的和整体的,完全推广到Finsler几何,而且很简单。因此,我觉得以后的微分几何课或Riemann几何课都应该讲一般情形.最近有几个拓扑问题.最主要的一个是Riemann流形的一个重要性质,即英国数学家Hodge的调和积分。现在有2个年轻人,一个是David Bao, 另一个是他的美国学生,抒这个Hodge的调和积分推广到了Finsler情形。这将是微分几何的一块新园地,预料前景无限。1995年夏在美国西雅图有一Finsler几何的国际会议。其论文集已于今年由美国数学会出版.

    Finsler 几何在1900年有名的Hilbert演讲中是第23个问题。

7.中国的数学

    数学研究的最高标准是创造性:要达到前人未到的境界,要找着最深刻的关键。从另一点看,数学的范围,是无垠的。我愿借此机会介绍一下科学出版社从俄文翻译的《数学百科全书》,全书5大卷,每卷约千页。中国能出版这样的巨著,即是翻译,也是一项可喜的在就。这是一部十分完备的百科全书,值得赞扬的。

    对着如此的学问大海,入门必须领导,便需要权威性的学校和研究所。数学是活的,不断有杰出的贡献,令人赞赏佩服。但一个国家,比较可以集中某些方面,不必完全赶时髦。当年芬兰的复变函数论,波兰的纯粹数学,都是专精一门而有成就的例子。

    中国应该发展实力较强的方面。但由百科全书的例子,可看出中国的数学是全面的。这是一个可喜的现象。

    中国的财富在“人民”。中国的数学政策,除了鼓励尖端的研究以外,应该用来提高一般的数学水平。我有两个建议:(1)设立数学讲座,待遇从优,其资格可能是对数学发展有重大贡献的人;(2)设立新的数学中心,似乎成都,西安,广州都是可能的地点。中心应有相当的经费,部分可由地方负担,或私人筹措。近年因为国家开放,年轻人都想经商赚钱,当然国家社会需要这样的人。但是做科学的乐趣是一般不能理解的。在科学上做了基本的贡献,有历史的意义。我想对于许多人,这是一项了不得的成就。在岗位上专心学问,提携后进,“得天下之英才而教育之“,应该是十分愉快的事情。

    一个实际的问题,是个人应否读数学。Hardy 说,一个条件是看你是否比老师强。这也许太强一些。我想学习应不觉困难,读名著能很快与作者联系,都是测验。数学是小科学,可以关起门来做。在一个多面竞争的社会中,是一项有优点的职业,即使你有若干能力。

    中国的数学有相当水平。年来政治多变,达此情况,足风中华民族的勤劳本质。从前一个数学家的最高标准,是从国外名大学获得博士学位。我们国家现在所包需做的,是充实各大学的研究院,充实博士学位,人才由自己训练。

分类

 

3月 2010
« 7    
1234567
891011121314
15161718192021
22232425262728
293031  

Blogroll