再论自然数全加和 - 质数螺旋及其生成程序

这个图像被称为质数螺旋,其实是不恰当的。

实际上是自然数(包括0)从中心开始,按照螺旋的方式排列,并将其中的质数用白色表示出来,而显示的结果,0和1以及其它合数保持黑色。具体来说,图片的中心点为0,中心点的右下角像素为1,从1开始向上为2,然后是3,然后转向左侧,0的正上方为4,再向前为5,然后转向下方,0的左侧为6,在向下为7,然后转向右方,0的正下方为8,这就完成了从0到8一共9个数的第一个周期。第二个周期从8的右下方开始,然后贴着第一个周期进行环绕,一直到8的下方24,完成第二个周期。所有周期的开始都在图像中心偏右向下方延申的那条线上。以下为0到120之间的整数螺旋,其中质数被标为绿色。

以下是将近整个屏幕(分辨率1920*1200=2304000)将近200万个整数的螺旋,其中白色的点为质数,黑色的点不是(比如0和1既不是质数也不是合数).

这个图像的2D-FFT结果只有一个中间点

如果四个象限内部各自同时翻转横纵坐标,结果如图,

会出现明显的圈层纹路。

以下是实现上述图像的核心算法的程序代码

cs 复制代码
namespace PrimeCross;

public partial class FormMain : Form
{
    public FormMain()
    {
        InitializeComponent();
    }
    enum Direction : int
    {
        Down = 0,
        Right,
        Up,
        Left
    }

    Direction Turn(Direction d, bool left = true) => left
            ? (Direction)(((int)d + 1) % 4)
            : (d == Direction.Down) ? Direction.Left : ((Direction)((int)d) - 1)
        ;
    Point LeftOf(Point p, Direction d) => d switch
    {
        Direction.Down => new Point(p.X + 1, p.Y),
        Direction.Right => new Point(p.X, p.Y - 1),
        Direction.Up => new Point(p.X - 1, p.Y),
        Direction.Left => new Point(p.X, p.Y + 1),
        _ => p,
    };
    Point RightOf(Point p, Direction d) => d switch
    {
        Direction.Down => new Point(p.X - 1, p.Y),
        Direction.Right => new Point(p.X, p.Y + 1),
        Direction.Up => new Point(p.X + 1, p.Y),
        Direction.Left => new Point(p.X, p.Y - 1),
        _ => p,
    };

    Point ForwardOf(Point p, Direction d) => d switch
    {
        Direction.Down => new Point(p.X, p.Y + 1),
        Direction.Right => new Point(p.X + 1, p.Y),
        Direction.Up => new Point(p.X, p.Y - 1),
        Direction.Left => new Point(p.X - 1, p.Y),
        _ => p,
    };
    bool IsPrime(long n)
    {
        if (n < 2) return false;
        if (n == 2) return true;
        if (n % 2 == 0) return false;
        for (long i = 3; i <= Math.Sqrt(n); i += 2)
        {
            if (n % i == 0) return false;
        }
        return true;
    }
    const int Black = 0x000000;
    const int White = 0xffffff;
    const int Red = 0x0000ff;
    int length = 0;
    (int, long, bool)[,]? primes = null;
    (int, long, bool)[,] BuildPrimesMap(int length)
    {
        var map = new (int, long, bool)[length, length];
        Point center = new(length >> 1, length >> 1);
        var direction = Direction.Up;
        long n = 0;
        map[center.X, center.Y] = (White, n++, false);
        Point p = new(center.X + 1, center.Y + 1);
        map[p.X, p.Y] = (Red, n++, false);
        p.Y--;
        map[p.X, p.Y] = (White, n++, true);
        while (n <= length * length)
        {
            n++;
            p = ForwardOf(p, direction);
            if (p.X < 0 || p.X >= length - 1
                || p.Y < 0 || p.Y >= length - 1)
                break;
            var b = IsPrime(n);
            map[p.X, p.Y] = (b ? White : Red, n, b);

            var l = LeftOf(p, direction);
            if (l.X < 0 || l.X >= length - 1
                || l.Y < 0 || l.Y >= length - 1)
                break;
            var lc = map[l.X, l.Y];
            if (lc.Item1 == Black)
            {
                direction = Turn(direction);
            }
            else
            {
                var pt = ForwardOf(p, direction);
                if (pt.X < 0 || pt.X >= length - 1
                    || pt.Y < 0 || pt.Y >= length - 1)
                {
                    continue;
                }

                var px = map[pt.X, pt.Y];

                if (px.Item1 != Black)
                {
                    var rp = RightOf(p, direction);
                    if (rp.X < 0 || rp.X >= length - 1
                        || rp.Y < 0 || rp.Y >= length - 1)
                        break;
                    p = rp;
                }
            }
        }
        return map;
    }
    private void GenerateButton_Click(object sender, EventArgs e)
    {
        this.length = Math.Max(PrimesPictureBox.Width, PrimesPictureBox.Height);
        this.primes = BuildPrimesMap(this.length);

        var bitmap = new Bitmap(PrimesPictureBox.Width, PrimesPictureBox.Height);

        for (int y = 0; y < PrimesPictureBox.Height; y++)
        {
            for (int x = 0; x < PrimesPictureBox.Width; x++)
            {
                var px = x + ((this.length - PrimesPictureBox.Width) >> 1);
                var py = y + ((this.length - PrimesPictureBox.Height) >> 1);
                var c = this.primes[px, py];
                bitmap.SetPixel(x, y, c.Item3 ? Color.White : Color.Black);
            }
        }

        this.PrimesPictureBox.Image?.Dispose();
        this.PrimesPictureBox.Image = bitmap;

    }

    private void FormMain_Resize(object sender, EventArgs e)
    {
        this.GenerateButton_Click(sender, e);
    }

    private void FormMain_Load(object sender, EventArgs e)
    {
        this.GenerateButton_Click(sender, e);
    }

    private void PrimesPictureBox_MouseMove(object sender, MouseEventArgs e)
    {
        if (this.primes != null && PrimesPictureBox.Image != null)
        {
            var x = e.X + ((PrimesPictureBox.Image.Width - PrimesPictureBox.Width) >> 1);
            var y = e.Y + ((PrimesPictureBox.Image.Height - PrimesPictureBox.Height) >> 1);

            if (x >= 0 && x < PrimesPictureBox.Image.Width
                && y >= 0 && y < PrimesPictureBox.Image.Height)
            {
                PointF cp = new(PrimesPictureBox.Image.Width >> 1, PrimesPictureBox.Image.Height >> 1);
                PointF dp = new(x - cp.X, cp.Y - y);

                PointF mp = new(dp.X + (this.length >> 1), dp.Y + (this.length >> 1));
                var p = this.primes![(int)mp.X, (int)mp.Y];
                long n = p.Item2;
                bool b = p.Item3;
                var t = Math.Atan2(dp.Y, dp.X) / Math.PI * 180.0;
                this.InfoLabel.Text = $"n={n}, x={dp.X}, y={dp.Y}, d={t:N4}°: {(b ? "Prime" : "Composite")}";
            }
        }
    }
}

https://github.com/yyl-20020115/PrimeCross.git

缩小版本看的更清楚,

相关推荐
niuniudengdeng36 分钟前
六面独立转动魔方还原机器人设计与实现
数学·算法·机器人
ghie909037 分钟前
基于MATLAB的A*算法避障路径规划实现
人工智能·算法·matlab
雾岛听蓝1 小时前
C文件操作与系统IO
linux·c语言·开发语言·经验分享·笔记·算法
zh路西法1 小时前
【宇树机器人强化学习】(一):PPO算法的python实现与解析
python·深度学习·算法·机器学习·机器人
随意起个昵称1 小时前
【贪心】选择尽量多的不相交区间
数据结构·算法
章小幽1 小时前
LeetCode-35.搜索插入位置
数据结构·算法·leetcode
放下华子我只抽RuiKe52 小时前
机器学习全景指南-探索篇——发现数据内在结构的聚类算法
人工智能·深度学习·算法·机器学习·语言模型·数据挖掘·聚类
Yupureki2 小时前
《C++实战项目-高并发内存池》3.ThreadCache构造
服务器·c语言·c++·算法·哈希算法
j_xxx404_2 小时前
C++算法:一维/二维前缀和算法模板题
开发语言·数据结构·c++·算法
x_xbx2 小时前
LeetCode:111. 二叉树的最小深度
算法·leetcode·职场和发展