Aug 17

    考虑函数f(z)=z^2-0.75。固定z0的值后,我们可以通过不断地迭代算出一系列的z值:z1=f(z0), z2=f(z1), z3=f(z2), ...。比如,当z0 = 1时,我们可以依次迭代出:
z1 = f(1.0) = 1.0^2 - 0.75 = 0.25
z2 = f(0.25) = 0.25^2 - 0.75 = -0.6875
z3 = f(-0.6875) = (-0.6875)^2 - 0.75 = -0.2773
z4 = f(-0.2773) = (-0.2773)^2 - 0.75 = -0.6731
z5 = f(-0.6731) = (-0.6731)^2 - 0.75 = -0.2970
...
    可以看出,z值始终在某一范围内,并将最终收敛到某一个值上。
    但当z0=2时,情况就不一样了。几次迭代后我们将立即发现z值最终会趋于无穷大:
z1 = f(2.0) = (2.0)^2 - 0.75 = 3.25
z2 = f(3.25) = (3.25)^2 - 0.75 = 9.8125
z3 = f(9.8125) = (9.8125)^2 - 0.75 = 95.535
z4 = f(95.535) = (95.535)^2 - 0.75 = 9126.2
z5 = f(9126.2) = (9126.2)^2 - 0.75 = 83287819.2
...
    经过计算,我们可以得到如下结论:当z0属于[-1.5, 1.5]时,z值始终不会超出某个范围;而当z0小于-1.5或大于1.5后,z值最终将趋于无穷。
    现在,我们把这个函数扩展到整个复数范围。对于复数z0=x+iy,取不同的x值和y值,函数迭代的结果不一样:对于有些z0,函数值约束在某一范围内;而对于另一些z0,函数值则发散到无穷。由于复数对应平面上的点,因此我们可以用一个平面图形来表示,对于哪些z0函数值最终趋于无穷,对于哪些z0函数值最终不会趋于无穷。我们用深灰色表示不会使函数值趋于无穷的z0;对于其它的z0,我们用不同的颜色来区别不同的发散速度。由于当某个时候|z|>2时,函数值一定发散,因此这里定义发散速度为:使|z|大于2的迭代次数越少,则发散速度越快。这个图形可以编程画出。和上次一样,我用Pascal语言,因为我不会C的图形操作。某个MM要过生日了,我把这个自己编程画的图片送给她^_^

{$ASSERTIONS+}

uses graph;

type
   complex=record
      re:real;
      im:real;
   end;

operator * (a:complex; b:complex) c:complex;
begin
   c.re := a.re*b.re - a.im*b.im;
   c.im := a.im*b.re + a.re*b.im;
end;

operator + (a:complex; b:complex) c:complex;
begin
   c.re := a.re + b.re;
   c.im := a.im + b.im;
end;

var
   z,c:complex;
   gd,gm,i,j,k:integer;
begin
   gd:=D8bit;
   gm:=m640x480;
   InitGraph(gd,gm,'');
   Assert(graphResult=grOk);

   c.re:=-0.75;
   c.im:=0;
   for i:=-300 to 300 do
   for j:=-200 to 200 do
   begin
      z.re:=i/200;
      z.im:=j/200;
      for k:=0 to 200 do
      begin
         if sqrt(z.re*z.re + z.im*z.im) >2 then break
         else z:=(z*z)+c;
      end;
      PutPixel(i+300,j+200,k)
   end;

   readln;
   CloseGraph;
end.


    代码在Windows XP SP2,FPC 2.0下通过编译,麻烦大家帮忙报告一下程序运行是否正常(上次有人告诉我说我写的绘图程序不能编译)。在我这里,程序运行的结果如下:



    这个美丽的分形图形表现的就是f(z)=z^2-0.75时的Julia集。考虑复数函数f(z)=z^2+c,不同的复数c对应着不同的Julia集。也就是说,每取一个不同的c你都能得到一个不同的Julia集分形图形,并且令人吃惊的是每一个分形图形都是那么美丽。下面的六幅图片是取不同的c值得到的分形图形。你可能不相信这样一个简单的构造法则可以生成这么美丽的图形,这没什么,你可以改变上面程序代码中c变量的值来亲自验证。

c = 0.45, -0.1428
  

c = 0.285, 0.01
  

c = 0.285, 0
  

c = -0.8, 0.156
  

c = -0.835, -0.2321
  

c = -0.70176, -0.3842
  



    类似地,我们固定z0=0,那么对于不同的复数c,函数的迭代结果也不同。由于复数c对应平面上的点,因此我们可以用一个平面图形来表示,对于某个复数c,函数f(z)=z^2+c从z0=0开始迭代是否会发散到无穷。我们同样用不同颜色来表示不同的发散速度,最后得出的就是Mandelbrot集分形图形:
    

    前面说过,分形图形是可以无限递归下去的,它的复杂度不随尺度减小而消失。Mandelbrot集的神奇之处就在于,你可以对这个分形图形不断放大,不同的尺度下你所看到的景象可能完全不同。放大到一定时候,你可以看到更小规模的Mandelbrot集,这证明Mandelbrot集是自相似的。下面的15幅图演示了Mandelbrot集的一个放大过程,你可以在这个过程中看到不同样式的分形图形。







网上可以找到很多小程序实现Mandelbrot集的放大过程。把上面给出的代码改一改,你也可以写出一个这样的程序来。
做人要厚道,转贴请注明出处

Jul 3

昨天在digg上看到了一个交互式小游戏,觉得很有意思,于是自己也写了一个,花了一个上午的时间。

http://www.matrix67.com/guessword/guess.asp
有bug的话请报告一下。

2007.07.08 想加入聊天、留言等功能,但如何排版是一个问题

May 31

Current Version : 0.11
Last Update : 2007-05-31
Author : Matrix67.com

Click here to download (Do not directly link to this file)

This program is a batch extractor which exports album covers embedded in mp3 ID3v2 tags. Run pic_extractor.exe under Windows, it will search all mp3 files in the directory, export pictures in ID3v2 tags. Output filenames are formatted as "artist - album". Note that the artist and album info is taken from ID3v1, because the encoding of ID3v2 may vary. If there's no ID3v1 tag contained in your mp3 file, you may need some other powerful ID3 tools (ID3-TagIT fits me well) so you can transfer ID3v2 tags to ID3v1 tags. If there's any invalid character for filename (like '?', '\', '*') or ID3v1 tag doesn't exist, filename changes to "FilenameError", followed by a sequence number.

If you have any suggestion, advice or bug report, feel free to mail me at gs.matrix67@gmail.com, or you can just leave a message below.

Source code can be found here.

May 11

英文发布页:http://www.matrix67.com/blog/article.asp?id=259

0.11版发布,主要更新如下:

  • 使用二进制方式打开文件,加快程序运行速度(处理我的600多个mp3文件不到半分钟)
  • 自动检测重复专辑,同一专辑只写一次文件
  • 修正当ID3v1中有发行年份、歌曲类型等信息时发生的错误
  • 修正找不到ID3v1时歌曲名出现乱码的错误
  • 修正没有专辑图片时错误输出文件的问题
  • 修正查找文件时漏掉部分文件的错误
  • 识别更多的图片类型
  • 其它一些小的修改


点击此处下载

    转移系统平台后我试用了一大柄的音乐播放软件,最后还是选择了RhythmBox。对于我来说,RhythmBox的唯一缺点就是不支持mp3内部的专辑图片,而我的mp3文件全部都是标签嵌入的图片。RhythmBox可以通过读取~/.gnome2/rhythmbox/covers下“歌手 - 专辑名”格式的文件名来显示图片,于是我想到找个软件来批量导出专辑图片。没想到我把google翻了个底朝天都没找到这样的程序,一狠心打算自己写一个。
    这个程序估计会有需要用的人,因此作为0.1 beta版发布在这里。现在已经发布了0.11版。我对这个小程序的开发比较感兴趣,任何觉得有需求的人可以在下面留言。发现Bug请帮忙报告一下(这句话说了N多次都没人回应)。

    程序是在Windows下编写的。和上次一样,目前暂时不打算用Delphi(除非我要接着做下去)。C语言的文件操作还不怎么过关,只好又拿Free Pascal写了。

使用方法(请仔细阅读,发生任何意外我不负责!)
    由于这是一个测试版,请先备份好你的mp3文件以防不测(其实一般不会发生问题,程序不写mp3文件)。下载该rar文件并解压,你会看到一个.exe文件。 将这个文件拷贝至你的mp3目录下,运行该文件后程序将扫描该目录下的所有mp3文件并寻找可能的内嵌图片,以ID3v1信息来命名图片文件,文件名格式为“歌手 - 专辑名”。相同文件名自动覆盖(这样的话你的专辑图片就是唯一的)。之所以不用ID3v2是因为ID3v2的编码不确定,我暂时不想处理Unicode。如果你的mp3里没有ID3v1标签,你可以随便找一个工具把ID3v2转为ID3v1,推荐用ID3-TagIt。建议你先复制少许mp3文件到新的文件夹试用一下。

    以下情况可能导致错误:
    1. mp3文件里嵌入多个图片或有图片说明(如果你是iTunes用户应该没问题);
    2. ID3v1里有Windows不允许作为文件名的字符;
    3. 不存在ID3v1或需要的ID3v1信息不全。
    发生后两种情况时,文件名将用FilenameError加数字编号代替。

Matrix67原创
转贴请注明出处

    如果有人感兴趣的话,附程序代码:
program pic_extractor;
// -------------------------
// Current Version : 0.11
// Last Update : 2007-05-31
// Author : Matrix67.com
// -------------------------

// ----------------------------------------------------
// This program is a batch extractor which exports album
// covers embedded in mp3 ID3v2 tags. Compiled version can
// be found at http://www.matrix67.com/blog/article.asp?id=240
// Version 0.11 tested under Windows XP SP2, Free Pascal 2.0
// Next version will be written in Delphi.
// ----------------------------------------------------

uses dos,sysutils;

var
     PictureType: string;     // .png|.jpg|.bmp|.gif
     FailCount  : longint=0;  // Number of Invalid Filenames
     AlbumCount : longint=0;  // Number of Albums
     FileHandle : longint;

     PicBuffer   : array[1..1100000]of char;
     InfoBuffer  : array[1..210]of char;
     FileNameDone: array[1..1100]of string[70];
       // FileNameDone[AlbumCount]:=OutputFileName

function SameAlbum(OutputFileName:string):boolean;
var
   i:longint;
begin
   for i:=1 to AlbumCount do
      if FileNameDone[i] = OutputFileName then exit(true);
   inc(AlbumCount);
   FileNameDone[ AlbumCount ] :=OutputFileName;
   exit(false);
end;

function FindAPIC:longint;
// --------------------------------------------------------------
//  This function will search the entire tag for APIC tag frame.
//  Error may occur if there happens to be another 'APIC' string.
//  Bugs will be fixed in next version.
// --------------------------------------------------------------
var
   Scanner:string='    ';
   FrameLength : longint=0;
   Id3Length   : longint=0;
   identifier  : integer;

   procedure ReadFrame(var ch:char);
   begin
      FileRead( FileHandle , ch , SizeOf(ch) );
      dec(FrameLength);
   end;

var
   i:longint;
   ch:char;

begin
   // Check if ID3 Tag Exists
   FileRead( FileHandle, identifier, 2);
   if identifier<>$4449 then exit(-1);

   // Get Size of ID3 Tag
   FileSeek( FileHandle, 4, fsFromCurrent);
   for i:=1 to 4 do
   begin
      FileRead( FileHandle , ch , SizeOf(ch) );
      Id3Length:=Id3Length shl 7 + ord(ch);
   end;

   // Search for APIC header
   repeat
      FileRead( FileHandle , ch , SizeOf(ch) );
      dec(Id3Length);
      delete(Scanner, 1, 1);
      Scanner:=Scanner+ch;
      if Scanner='APIC' then break;
   until Id3Length=0;
   if Scanner<>'APIC' then exit(-1);

   // Calculate size of APIC frame
   for i:=1 to 4 do
   begin
      FileRead( FileHandle , ch , SizeOf(ch) );
      FrameLength:=FrameLength shl 8 + ord(ch);
   end;
   for i:=1 to 2 do FileRead( FileHandle , ch , SizeOf(ch) );

   // Filename Extension
   repeat ReadFrame(ch) until ch='/';
   ReadFrame(ch);
   if ch='j' then PictureType:='jpg'
      else if ch='p' then PictureType:='png'
      else if ch='b' then PictureType:='bmp'
      else if ch='g' then PictureType:='gif'
      else PictureType:='ukn';  // Unknown

   // Drop some useless bits.
   // Error may occur if any comment or type description exists.
   repeat ReadFrame(ch) until ch=#0;
   for i:=1 to 2 do ReadFrame(ch);

   FileRead( FileHandle , PicBuffer , FrameLength );
   exit(FrameLength);
end;


function FindOutputFileName:string;
// ------------------------------------------------------------------
// This function reads the very end of file for getting ID3v1 tag.
// Filename will be generated using "Artist - Album" format. We use ID3v1
// instead of ID3v2 because the encoding of ID3v2 may vary. This program
// can only handle GBK encodings. Files without ID3v1 lead to invalid
// filenames.
// ------------------------------------------------------------------

var
   FindResult:string='';
   i:longint;

begin
   FileSeek( FileHandle , -128 , fsFromEnd );
   FileRead( FileHandle , InfoBuffer , 128 );

   // Identifier of ID3v1
   // If no ID3v1 found, exit invalid characters for filename.
   if InfoBuffer[1]+InfoBuffer[2]+InfoBuffer[3]<>'TAG' then exit('? - ?');

   // Name of Album
   i:=34;
   while InfoBuffer[i]<>#0 do
   begin
      FindResult:=FindResult+InfoBuffer[i];
      inc(i);
   end;

   // Filename Format : Artist - Album
   // This format fits Rhythmbox well
   // Format can be customized in further
   FindResult:=FindResult + ' - ';

   // Name of Artist
   i:=64;
   while InfoBuffer[i]<>#0 do
   begin
      FindResult:=FindResult+InfoBuffer[i];
      inc(i);
   end;

   exit(FindResult);
end;

procedure SavePic( var OutputFileName:string; FrameLength:longint );
// ------------------------------------------------------
// Save the extracted picture with the filename provided
// by FindOutputFileName Function. Output directory and
// overwrite option will be added in GUI version.
// ------------------------------------------------------
var
   FailedNum:string;
begin
   FileHandle:=FileCreate(OutputFileName + '.' + PictureType);
   if FileHandle=-1 then
   begin
      // Error caused by invalid characters, Changing Filename
      inc(FailCount);
      str(FailCount,FailedNum);
      OutputFileName:='FilenameError' + FailedNum;
      FileHandle:=FileCreate(OutputFileName + '.' + PictureType);
   end;

   FileWrite( FileHandle , PicBuffer , FrameLength );
   FileClose( FileHandle );
end;

procedure main;
var
   FrameLength    : longint;
   OutputFileName : string;
   LastFileName   : string;
   dir:TSearchRec;

begin
   FindFirst( '*.mp3', faAnyFile and not (faVolumeID or faDirectory), Dir);
   while (DosError=0) do
   begin
      LastFileName:=Dir.name;
      FileHandle:=FileOpen(Dir.name,fmOpenRead);
      if FileHandle=-1 then halt;

      write(Dir.name + ' -->  ');

      FrameLength := FindAPIC;
      OutputFileName := FindOutputFileName;
      FileClose( FileHandle );

      if SameAlbum(OutputFileName) then
         writeln('Same Album Cover Already Extracted.')
      else if FrameLength=-1 then
         writeln('Album Cover Not Found.')
      else begin
         SavePic(OutputFileName , FrameLength);
         write('Found Album Cover, Saved as "');
         writeln(OutputFileName + '.' + PictureType + '"');
      end;

      FindNext(Dir);
      if Dir.name=LastFileName then halt;
   end;

   FindClose(Dir);
end;

begin
   main;
end.

May 3


    和大家一样,我也是一个G饭,将百度设为默认搜索引擎的唯一一个原因仅仅是上网看到了不认识的单词后,鼠标选中一拖(用了Drag de Go)就可以看到百度词典的链接。有时也会用一下搜狗,因为搜狗还有一个显示偏僻字读音的功能。今天没事干,打算写一个Greasemonkey脚本让Google显示搜索关键字的读音和释义(中英文都可以)。
    花了大概两个小时,具体方法是给Dict.cn发送XMLhttp请求,并把结果插入到Google页面中。我做人还算厚道,用了别人的东西是要链一下别人的,因此加了一个“View More”链接。不知道Google本身或者FireFox插件能不能实现这样的效果,反正我是没有找到。我想肯定有人需要这个,因此发布出来大家可以测试一下。

点击这里安装
注意:安装前请确认你正在使用FireFox并已经安装了Greasemonkey插件!
成功使用或有任何问题的同志在下面留个言


    目前我在FireFox 2.0和英文google环境下使用正常,大家发现Bug请帮忙报告一下。不过我好像每次叫大家报告Bug时都没人理我。
    目前已知问题:由于编码问题,中文关键字的“View More”链接无效。
    Matrix67原创,转贴请注明出处。

Apr 27

What is it?
    最近大家喜欢在留言板发一些与本站无关的话题并互相引用回复,这说明一个论坛模块是有必要的,于是想到了开发讨论区模块。
    这个单版面讨论区用于访问本站的网友进行讨论和聊天。它和留言板的功能有很大的区别。比如,下面8条消息中,前4条应该发到留言板,后4条应该发到讨论区。
    1. 这个Blog太他妈的牛了
    2. 为什么我要用代理才能上你的网?
    3. 建议把验证码换成3位乘法并加入平方和阶乘运算
    4. 申请友链www.8rong8chi.com,logo可以在www.3gedaibiao.com里找到
    5. 问一下Matrix67的情书那道题
    6. 记者MM的PP到手,请登陆www.colorwolf.com查看。
    7. 跪求Sky Angel Vol.39 - Vol.41和Tokyo Hot n0204
    8. matrix哥哥你好,我是一个可爱的初三MM,我好想跟你聊天啊,+我QQ:xxxxxxxx

    另外,针对某篇日志的留言直接在日志下面写评论就可以了。

History:
    23号的日志里我曾经说过我要写一个PJBlog的单版面论坛模块。实际的工作是从昨天开始的。
    昨天一起床我就开始研究PJBlog的数据库和函数,经过两天两夜的奋战终于写出了一个大致成形的程序。目前这个模块属于VERY Beta版,只用了两个asp文件,里面有很多问题。数据库结构的合理性有待观察,因此数据有可能会重建从而导致数据丢失。目前论坛界面非常简陋,你进去看了别被吓到就是了。任何一个牛人也有菜的时候,如果以后我开发了什么大型web 2.0,我不会忘记今天我写的这个终极菜鸟程序。

Features:
    这个单版面论坛的程序特点就是没有任何特点,除了发帖回贴外这个论坛程序目前不支持任何其它的操作(如头像、签名、高亮、置顶、PM、积分、附件、交易等),并且以后也不打算支持。毕竟这是一个个人Blog的模块而已。
    这个单版面论坛的管理方式就是不进行任何管理。不删除任何帖子,不分版限制话题,用户无需注册即可发言。仅仅是一个大家随意交流的地方。各位在其它论坛发的水贴老被删的话可以到这里来(想不通OIBH为什么不开水区)。请大家自觉远离色情,远离政治。

TODO List:
    加入分页功能
    加入管理员的管理功能
    加入自动清除陈贴的功能
    将浏览方式改为纯Ajax
    一些简单的界面美化
    修复大家提出的Bug
    可能加入其它一些大家提出的有创意的构想

有Bug请报告一下。

Apr 19

很早就跟别人说我想搞Ajax,今天终于修成正果,实现了首页asp程序Ajax化。Ajax太他妈的牛了。
目前在我这里运行良好,有Bug的话报告一下。
目前已知问题:不支持Opera。目前还不知道是为什么,期待哪位高人给本菜鸟指点一下。现在Opera也可以了,原因出在cache上。

Apr 19

    常去mimima(已封,因此该asp程序不支持), 2kdown, pidown等种子host网站的同志都知道,这类站点有一个非常麻烦的地方就是不支持FireFox,点击Download后不能下载,而是出现一整页的乱码。上这种站点又怕有毒,开IE Tab开得胆战心惊的。今天搞烦了,决定把这个问题解决了。初步认为,错误原因应该是那边的php返回的Content-Type不对。然后,网上搜索半天解决方案都没有,于是想到自己写一个GreaseMonkey脚本,后来写来写去发现怎么也不行,又想搞FireFox扩展。最后突然想到办法,为什么不用asp把那边的数据用XMLhttp偷过来并转化成正确的Content-Type?于是,我的又一个asp小程序诞生了。
    这是一个测试版,可能有很多Bug,大家可以帮忙报告一下。这个asp程序在我这里还没出问题,至少上面提到的两个网站是完全可以的,我今天已经用了好几次了。注意,有一些其它的BT种子上传站点,虽然界面非常相似,但代码不一样(比如onlyff.com),它们是支持FireFox的,同时因为Post方式不一样,该asp程序不支持。

点击这里进入

需要测试一下么?你可以把下面的地址复制到输入框里然后点击Download。
http://www.pidown.com/link.php?ref=M70vw7SS8o
严重NSFW,别因为好奇真下了点开来看。我?我是满了18岁的了,下个月就19了。

    回过来想一下,JavaScript也可以XMLhttp,但是我不知道怎样用JS生成一个二进制文件。我想至少出于安全方面的考虑,这是不大可能的。

2007.04.22  pidown和2kdown也被封了,本asp程序彻底作废,关了。

« 更早的日志