News:

Masm32 SDK description, downloads and other helpful links
Message to All Guests
NB: Posting URL's See here: Posted URL Change

Main Menu

Riemann Zeta Function

Started by six_L, May 09, 2025, 11:06:09 PM

Previous topic - Next topic

six_L

Hi,all
Zeta(z)=1/1^z+1/2^z+1/3^z+...+1/n^z+...
n: All natural numbers
z = a+bi, a != 1
Zeta(z) trivial zeros: a = -2,-4,-6,...,-2n
Zeta(z) Nontrivial zeros: a = 1/2, b = ?(40%) [There isn't still strict proof now]
The Zeta(z) Nontrivial zeros are related to the count of prime numbers.

I drawed the Zeta(z) curve. but it is strange. Do you know how to draw the following left image?
Say you, Say me, Say the codes together for ever.

zedd

I havent a clue, but it looks very similar in some aspects to a cardioid polar pattern, at least the outermost curves.. except for the orientation.



Probably doesn't help you at all, but it was the first thing that came to mind when I saw your image on the left.


:biggrin:  :skrewy:

guga

#2
Try this (press R to reset animation). You can also save the generated image

Links below holds the full source (and solution database for VS2022)
https://www.mediafire.com/file/t4bxo1lgvc2bdm8/Zeta10.rar/file
https://www.mediafire.com/file/2axp5fyma44y6on/Zeta11.zip/file




// ZetaVisualizerFinal.c - Extended coordinate labels to match grid lines
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <objidl.h>
#include <gdiplus.h>
#include <math.h>
#include <stdio.h>
#include <time.h>
#include <commdlg.h>

#pragma comment(lib, "gdiplus.lib")
#pragma comment(lib, "user32.lib")
#pragma comment(lib, "gdi32.lib")

using namespace Gdiplus;

// Global variables for animation
static float animationProgress = 0.0f; // 0.0 to 1.0
static const float ANIMATION_SPEED = 0.005f; // Adjust for faster/slower animation
static const UINT_PTR ANIMATION_TIMER_ID = 1;
static bool isAnimationRunning = false; // Track animation state

// Complex number structure
typedef struct {
    double real;
    double imag;
} Complex;

// Improved Zeta function with better convergence
Complex Zeta(Complex s, int iterations) {
    Complex result = { 0.0, 0.0 };
    double running_sum = 0.0;

    // Standard Dirichlet series for first N terms
    for (int n = 1; n <= iterations; n++) {
        double term = 1.0 / pow(n, s.real);
        double angle = -s.imag * log(n);
        result.real += term * cos(angle);
        result.imag += term * sin(angle);

        if (n > 10 && fabs(result.real - running_sum) < 1e-10) {
            break;
        }
        running_sum = result.real;
    }

    // Add a simple Euler-Maclaurin correction for remainder
    if (iterations > 10) {
        int N = iterations;
        double term = 1.0 / pow(N + 1, s.real);
        double angle = -s.imag * log(N + 1);
        // Approximate remainder: integral term ~ 1/(s-1) * N^(1-s)
        double correction_real = term * cos(angle) / (s.real - 1.0);
        double correction_imag = term * sin(angle) / (s.real - 1.0);
        result.real += correction_real;
        result.imag += correction_imag;
    }

    return result;
}

// Draw the enhanced Zeta function visualization
void DrawEnhancedZeta(HDC hdc, int width, int height, float progress) {
    Graphics graphics(hdc);
    graphics.SetSmoothingMode(SmoothingModeAntiAlias);
    graphics.SetCompositingQuality(CompositingQualityHighQuality);
    graphics.SetTextRenderingHint(TextRenderingHintAntiAlias); // Improve text rendering

    // Dark gradient background
    LinearGradientBrush background(
        Point(0, 0),
        Point(width, height),
        Color(255, 10, 20, 50), // Deep blue
        Color(255, 0, 0, 0));  // Black
    graphics.FillRectangle(&background, 0, 0, width, height);

    // Set up coordinate system
    REAL centerX = width / 2.0f;
    REAL centerY = height / 2.0f;
    REAL scale = (REAL)min(width, height) / 4.0f;
    REAL unitScale = scale / 6.0f; // Pixels per unit (zeta.real or zeta.imag)

    // Draw subtle grid lines
    Pen gridPen(Color(50, 100, 100, 150), 0.3f);
    for (int i = -6; i <= 6; i++) {
        graphics.DrawLine(&gridPen,
            0.0f, centerY + i * scale / 3.0f,
            (REAL)width, centerY + i * scale / 3.0f);
        graphics.DrawLine(&gridPen,
            centerX + i * scale / 3.0f, 0.0f,
            centerX + i * scale / 3.0f, (REAL)height);
    }

    // Draw glowing axes
    LinearGradientBrush axisBrush(
        Point(0, (int)centerY),
        Point(width, (int)centerY),
        Color(150, 200, 200, 255),
        Color(50, 100, 100, 100));
    Pen axisPen(&axisBrush, 1.8f);
    graphics.DrawLine(&axisPen, 0.0f, centerY, (REAL)width, centerY);
    graphics.DrawLine(&axisPen, centerX, 0.0f, centerX, (REAL)height);

    // Draw critical line
    LinearGradientBrush criticalBrush(
        Point((int)centerX, 0),
        Point((int)centerX, height),
        Color(150, 255, 150, 50),
        Color(50, 100, 255, 50));
    Pen criticalPen(&criticalBrush, 2.0f);
    REAL criticalX = centerX + scale * 0.5f;
    graphics.DrawLine(&criticalPen, criticalX, 0.0f, criticalX, (REAL)height);

    // Draw Zeta function curve with animation
    const int iterations = 200;
    const double t_start = 0.0;
    const double t_end = 30.0;
    const double t_step = 0.02;
    double t_max = t_start + progress * (t_end - t_start); // Animate up to t_max

    GraphicsPath path;
    PointF prevPoint;
    bool firstPoint = true;

    for (double t = t_start; t <= t_max; t += t_step) {
        Complex s = { 0.5, t };
        Complex zeta = Zeta(s, iterations);

        REAL x = centerX + (REAL)zeta.imag * scale / 6.0f;
        REAL y = centerY - (REAL)zeta.real * scale / 6.0f;

        if (!firstPoint) {
            path.AddLine(prevPoint, PointF(x, y));
        }
        else {
            path.StartFigure();
            firstPoint = false;
        }
        prevPoint = PointF(x, y);
    }

    // Neon gradient for Zeta curve
    Color colors[] = {
        Color(200, 255, 50, 50),
        Color(200, 255, 165, 0),
        Color(200, 255, 0, 255),
        Color(200, 50, 50, 255)
    };
    REAL positions[] = { 0.0f, 0.33f, 0.67f, 1.0f };
    LinearGradientBrush pathBrush(
        Point(0, (int)(centerY - scale)),
        Point(0, (int)(centerY + scale)),
        Color(255, 255, 255, 255),
        Color(255, 255, 255, 255));
    pathBrush.SetInterpolationColors(colors, positions, 4);

    // Draw glow and main curve
    Pen glowPen(&pathBrush, 5.0f);
    glowPen.SetColor(Color(100, 255, 255, 255));
    graphics.DrawPath(&glowPen, &path);
    Pen zetaPen(&pathBrush, 2.5f);
    graphics.DrawPath(&zetaPen, &path);

    // Add annotations with adjusted positions
    Font font(L"Cambria Math", 16, FontStyleBold);
    Font smallFont(L"Cambria Math", 12, FontStyleRegular); // Smaller font for coordinate labels
    SolidBrush shadowBrush(Color(80, 0, 0, 0));
    SolidBrush textBrush(Color(255, 230, 230, 230));
    StringFormat format;
    format.SetAlignment(StringAlignmentCenter);

    // Title: "ζ(s) where s = ½ + ti" (top center)
    Font bigFont(L"Cambria Math", 20, FontStyleBold);
    graphics.DrawString(L"ζ(s) where s = ½ + ti", -1, &bigFont,
        PointF(centerX + 4.0f, 24.0f), &format, &shadowBrush);
    graphics.DrawString(L"ζ(s) where s = ½ + ti", -1, &bigFont,
        PointF(centerX, 20.0f), &format, &textBrush);

    // Critical line label: "Re(s) = ½" (right side, near critical line)
    graphics.DrawString(L"Re(s) = ½", -1, &font,
        PointF(criticalX + 4.0f, 60.0f), &format, &shadowBrush);
    graphics.DrawString(L"Re(s) = ½", -1, &font,
        PointF(criticalX, 56.0f), &format, &textBrush);

    // Axis label: "Im(ζ(s))" (right side)
    REAL imLabelX = (REAL)width - 100.0f;
    graphics.DrawString(L"Im(ζ(s))", -1, &font,
        PointF(imLabelX + 4.0f, centerY - 24.0f), &shadowBrush);
    graphics.DrawString(L"Im(ζ(s))", -1, &font,
        PointF(imLabelX, centerY - 20.0f), &textBrush);

    // Axis label: "Re(ζ(s))" (bottom center)
    graphics.DrawString(L"Re(ζ(s))", -1, &font,
        PointF(centerX + 14.0f, (REAL)height - 44.0f), &shadowBrush);
    graphics.DrawString(L"Re(ζ(s))", -1, &font,
        PointF(centerX + 10.0f, (REAL)height - 40.0f), &textBrush);

    // Add coordinate labels for horizontal axis (Im(ζ(s))): -12 to 12, step 2
    for (int i = -6; i <= 6; i++) {
        int value = i * 2; // Grid lines are at intervals of 2 units
        REAL xPos = centerX + value * unitScale;
        WCHAR label[16];
        swprintf(label, 16, L"%d", value);
        graphics.DrawString(label, -1, &smallFont,
            PointF(xPos + 2.0f, centerY + 16.0f), &format, &shadowBrush);
        graphics.DrawString(label, -1, &smallFont,
            PointF(xPos, centerY + 12.0f), &format, &textBrush);
    }

    // Add coordinate labels for vertical axis (Re(ζ(s))): -12 to 12, step 2
    StringFormat nearFormat;
    nearFormat.SetAlignment(StringAlignmentNear); // Left-align for vertical labels
    for (int i = -6; i <= 6; i++) {
        int value = i * 2; // Grid lines are at intervals of 2 units
        REAL yPos = centerY - value * unitScale; // Negative because screen y increases downward
        WCHAR label[16];
        if (value == 0) {
            swprintf(label, 16, L"0");
        }
        else {
            swprintf(label, 16, L"%di", value);
        }
        graphics.DrawString(label, -1, &smallFont,
            PointF(centerX - 30.0f + 2.0f, yPos + 2.0f), &nearFormat, &shadowBrush);
        graphics.DrawString(label, -1, &smallFont,
            PointF(centerX - 30.0f, yPos), &nearFormat, &textBrush);
    }

    // Add animated non-trivial zero markers
    double zeros[] = { 14.1347, 21.0220, 25.0109, 30.4249 }; // Known zeros
    int numZeros = sizeof(zeros) / sizeof(zeros[0]);
    for (int i = 0; i < numZeros; i++) {
        if (zeros[i] <= t_max) { // Only draw zeros up to current progress
            Complex s = { 0.5, zeros[i] };
            Complex zeta = Zeta(s, iterations);
            REAL x = centerX + (REAL)zeta.imag * scale / 6.0f;
            REAL y = centerY - (REAL)zeta.real * scale / 6.0f;

            LinearGradientBrush zeroBrush(
                Point((int)(x - 10.0f), (int)(y - 10.0f)),
                Point((int)(x + 10.0f), (int)(y + 10.0f)),
                Color(200, 255, 100, 100),
                Color(0, 255, 255, 255));
            graphics.FillEllipse(&zeroBrush, x - 7.0f, y - 7.0f, 14.0f, 14.0f);

            Pen zeroPen(Color(150, 255, 255, 255), 1.0f);
            graphics.DrawEllipse(&zeroPen, x - 7.0f, y - 7.0f, 14.0f, 14.0f);
        }
    }
}

// Helper function to get PNG encoder CLSID
int GetEncoderClsid(const WCHAR* format, CLSID* pClsid) {
    UINT num = 0, size = 0;
    Gdiplus::GetImageEncodersSize(&num, &size);
    if (size == 0) return -1;

    ImageCodecInfo* pImageCodecInfo = (ImageCodecInfo*)(malloc(size));
    Gdiplus::GetImageEncoders(num, size, pImageCodecInfo);

    for (UINT j = 0; j < num; ++j) {
        if (wcscmp(pImageCodecInfo[j].MimeType, format) == 0) {
            *pClsid = pImageCodecInfo[j].Clsid;
            free(pImageCodecInfo);
            return j;
        }
    }

    free(pImageCodecInfo);
    return -1;
}

// Save visualization as PNG
void SaveAsPng(HWND hWnd, int width, int height, const WCHAR* filename) {
    // Create a bitmap
    Bitmap bitmap(width, height, PixelFormat32bppARGB);
    Graphics bitmapGraphics(&bitmap);
    bitmapGraphics.SetSmoothingMode(SmoothingModeAntiAlias);
    bitmapGraphics.SetCompositingQuality(CompositingQualityHighQuality);
    bitmapGraphics.SetTextRenderingHint(TextRenderingHintAntiAlias);

    // Draw the full visualization (progress = 1.0)
    HDC hdc = bitmapGraphics.GetHDC();
    DrawEnhancedZeta(hdc, width, height, 1.0f);
    bitmapGraphics.ReleaseHDC(hdc);

    // Save as PNG
    CLSID clsid;
    if (GetEncoderClsid(L"image/png", &clsid) != -1) {
        bitmap.Save(filename, &clsid, NULL);
        char msg[512];
        snprintf(msg, sizeof(msg), "Visualization saved as %S", filename);
        MessageBoxA(hWnd, msg, "Success", MB_OK | MB_ICONINFORMATION);
    }
    else {
        MessageBoxA(hWnd, "Failed to save PNG: PNG encoder not found", "Error", MB_OK | MB_ICONERROR);
    }
}

// Open file dialog for saving PNG
void ShowSaveDialog(HWND hWnd, int width, int height) {
    WCHAR filename[MAX_PATH] = L"ZetaVisualization.png";
    OPENFILENAMEW ofn = { 0 };
    ofn.lStructSize = sizeof(OPENFILENAMEW);
    ofn.hwndOwner = hWnd;
    ofn.lpstrFilter = L"PNG Files (*.png)\0*.png\0All Files (*.*)\0*.*\0";
    ofn.lpstrFile = filename;
    ofn.nMaxFile = MAX_PATH;
    ofn.lpstrDefExt = L"png";
    ofn.Flags = OFN_OVERWRITEPROMPT | OFN_PATHMUSTEXIST;

    if (GetSaveFileNameW(&ofn)) {
        SaveAsPng(hWnd, width, height, filename);
    }
}

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
    static int width, height;

    switch (message) {
    case WM_CREATE:
        // Animation starts paused; no timer set initially
        break;

    case WM_TIMER:
        if (wParam == ANIMATION_TIMER_ID) {
            animationProgress += ANIMATION_SPEED;
            if (animationProgress > 1.0f) {
                animationProgress = 1.0f; // Stop at full progress
                KillTimer(hWnd, ANIMATION_TIMER_ID);
                isAnimationRunning = false;
            }
            InvalidateRect(hWnd, NULL, FALSE); // FALSE to avoid background erase
        }
        break;

    case WM_PAINT: {
        PAINTSTRUCT ps;
        HDC hdc = BeginPaint(hWnd, &ps);

        RECT rect;
        GetClientRect(hWnd, &rect);
        width = rect.right;
        height = rect.bottom;

        // Create double buffer
        HDC memDC = CreateCompatibleDC(hdc);
        HBITMAP memBitmap = CreateCompatibleBitmap(hdc, width, height);
        HBITMAP oldBitmap = (HBITMAP)SelectObject(memDC, memBitmap);

        // Fill background to avoid artifacts
        HBRUSH blackBrush = (HBRUSH)GetStockObject(BLACK_BRUSH);
        FillRect(memDC, &rect, blackBrush);

        // Draw to memory DC
        DrawEnhancedZeta(memDC, width, height, animationProgress);

        // Copy to screen
        BitBlt(hdc, 0, 0, width, height, memDC, 0, 0, SRCCOPY);

        // Clean up
        SelectObject(memDC, oldBitmap);
        DeleteObject(memBitmap);
        DeleteDC(memDC);

        EndPaint(hWnd, &ps);
        break;
    }
    case WM_SIZE:
        width = LOWORD(lParam);
        height = HIWORD(lParam);
        InvalidateRect(hWnd, NULL, TRUE);
        break;

    case WM_COMMAND:
        switch (LOWORD(wParam)) {
        case 1001: // Save As
            ShowSaveDialog(hWnd, width, height);
            break;
        case 1002: // Start Animation
            if (!isAnimationRunning) {
                SetTimer(hWnd, ANIMATION_TIMER_ID, 16, NULL); // ~60 FPS
                isAnimationRunning = true;
            }
            break;
        case 1003: // Pause Animation
            if (isAnimationRunning) {
                KillTimer(hWnd, ANIMATION_TIMER_ID);
                isAnimationRunning = false;
            }
            break;
        }
        break;

    case WM_KEYDOWN:
        if (wParam == 'R') { // Reset animation
            animationProgress = 0.0f;
            if (!isAnimationRunning) {
                SetTimer(hWnd, ANIMATION_TIMER_ID, 16, NULL);
                isAnimationRunning = true;
            }
            InvalidateRect(hWnd, NULL, FALSE);
        }
        break;

    case WM_DESTROY:
        if (isAnimationRunning) {
            KillTimer(hWnd, ANIMATION_TIMER_ID);
        }
        PostQuitMessage(0);
        break;

    default:
        return DefWindowProcA(hWnd, message, wParam, lParam);
    }
    return 0;
}

int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
    GdiplusStartupInput gdiplusStartupInput;
    ULONG_PTR gdiplusToken;
    GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);

    // Create menu
    HMENU hMenu = CreateMenu();
    HMENU hFileMenu = CreatePopupMenu();
    AppendMenuA(hFileMenu, MF_STRING, 1001, "Save As...");
    AppendMenuA(hFileMenu, MF_STRING, 1002, "Start Animation");
    AppendMenuA(hFileMenu, MF_STRING, 1003, "Pause Animation");
    AppendMenuA(hMenu, MF_POPUP, (UINT_PTR)hFileMenu, "File");

    WNDCLASSA wc = { 0 };
    wc.lpfnWndProc = WndProc;
    wc.hInstance = hInstance;
    wc.lpszClassName = "ZetaVisualizer";
    wc.hCursor = LoadCursorA(NULL, IDC_ARROW);
    wc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
    RegisterClassA(&wc);

    HWND hWnd = CreateWindowA("ZetaVisualizer", "Riemann Zeta Function Visualizer",
        WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT,
        1200, 900, NULL, hMenu, hInstance, NULL);

    ShowWindow(hWnd, nCmdShow);
    UpdateWindow(hWnd);

    MSG msg;
    while (GetMessageA(&msg, NULL, 0, 0)) {
        TranslateMessage(&msg);
        DispatchMessageA(&msg);
    }

    DestroyMenu(hMenu);
    GdiplusShutdown(gdiplusToken);
    return (int)msg.wParam;
}

Attached the binary file. And on the links, the full source
Coding in Assembly requires a mix of:
80% of brain, passion, intuition, creativity
10% of programming skills
10% of alcoholic levels in your blood.

My Code Sites:
http://rosasm.freeforums.org
http://winasm.tripod.com

jack

#3
hi guga
I did a zeta approximation in FreeBasic years ago using the following
    '  f(k)=(k+nc)^-n

    '  inf          nc              inf                        inf
    '  ====          ====          /                          ==== B
    '  \      1    \      1      [                          \    (2*k)  (2*k-1)
    '  >    ----- =  >    ----- +  I    f(k) dk + B * f(0) -  >  ------ f  (0)
    '  /      n      /      n      ]              1          /    (2*k)!
    '  ====  k      ====  k      /                          ====
    '  k = 1        k = 1          0                          k = 1
I posted the code here https://www.freebasic.net/forum/viewtopic.php?p=193860#p193860

guga

Quote from: jack on May 10, 2025, 01:27:48 AMhi guga
I did a zeta approximation in FreeBasic years ago using the following
    '  f(k)=(k+nc)^-n

    '  inf           nc              inf                        inf
    '  ====          ====           /                          ==== B
    '  \       1     \       1      [                          \    (2*k)   (2*k-1)
    '   >    ----- =  >    ----- +  I    f(k) dk + B * f(0) -   >   ------ f  (0)
    '  /      n      /      n       ]               1          /    (2*k)!
    '  ====  k       ====  k       /                           ====
    '  k = 1         k = 1          0                          k = 1
I can post the code if anyone is interested

Tks, Jack. It would be good to see the code. Maybe it can later be ported to masm or even plain C if needed
Coding in Assembly requires a mix of:
80% of brain, passion, intuition, creativity
10% of programming skills
10% of alcoholic levels in your blood.

My Code Sites:
http://rosasm.freeforums.org
http://winasm.tripod.com

jack

I edited my post with a link to the source

guga

#6
Quote from: jack on May 10, 2025, 01:36:15 AMI edited my post with a link to the source

Tks, try this. Grok ported your version.

https://www.mediafire.com/file/bpmn4b5pj74ka2m/Zeta12.rar/file


Coding in Assembly requires a mix of:
80% of brain, passion, intuition, creativity
10% of programming skills
10% of alcoholic levels in your blood.

My Code Sites:
http://rosasm.freeforums.org
http://winasm.tripod.com

jack

hey guga
Grok explained what the code does better than my comments in my code  :biggrin:

guga

Quote from: jack on May 10, 2025, 07:39:56 AMhey guga
Grok explained what the code does better than my comments in my code  :biggrin:
Indeed :biggrin: Grok  is a wonderful tool. I started 1st using deepseek to create some basic app that worked similar to the left image that  six_L  showed. But, the result was inaccurate. Nevertheless, i took the code generated on deepseek and used it through Grok (the x version and not the one from the site) to it fix the code and make it more similar to the image, enhancing graphics and focusing in using gdi+. It fixed and i started to play with it, adding animation, a menu etc. Then when you uploaded your freebasic version, since i already had the skeleton, i mainly asked Grok to adapt the code he just did in C to yours in freebasic.

Grok does a very good work in Plain C language, but still lack the same skill in what concerns assembly (no matter if for masm, rosasm, fasm or nasm). For assembly programming you must not trust 100% on the generated code, but use it mainly as a guidance to improve yours.

In any case, the results i´ve seen so far are good enough to save some time in development. Most likely, until the end of the year i believe Grok (and others) should be more advanced in what is related to assembly language to save us even more time for coding.

One thing interesting, i have no idea what is this zeta all about. I only realized what was that, after pasting the comments  six_L  did on deepseek and ask him to do an app based on this. The rest, was fine tunned with Grok.

I started on deepseek, simply inserting this:

QuotePls create me a function in plain C using Gdi+ on a way i can generate the graphic on this link (image on left)https://masm32.com/board/index.php?action=dlattach;attach=18375;image. The goal is: Hi,all
Zeta(z)=1/1^z+1/2^z+1/3^z+...+1/n^z+...
n: All natural numbers
z = a+bi, a != 1
Zeta(z) trivial zeros: a = -2,-4,-6,...,-2n
Zeta(z) Nontrivial zeros: a = 1/2, b = ?(40%) [There isn't still strict proof now]
The Zeta(z) Nontrivial zeros are related to the count of prime numbers.

I drawed the Zeta(z) curve. but it is strange. Do you know how to draw the following left image?

And that was all it was needed to it create a zeta visualizer in C. Then, as i said, i used the generated code in x for fine tune and fix it.
Coding in Assembly requires a mix of:
80% of brain, passion, intuition, creativity
10% of programming skills
10% of alcoholic levels in your blood.

My Code Sites:
http://rosasm.freeforums.org
http://winasm.tripod.com

six_L

Hi,zedd/guga/jack
Thanks your help.
Quite useful information.
I am very interested in your Zeta algorithms. I need to learn hardly.

Zeta(z)=1/1^z+1/2^z+1/3^z+...+1/n^z+...
=1/(1-1/2^z) * 1/(1-1/3^z) * 1/(1-1/5^z) * 1/(1-1/7^z) * 1/(1-1/11^z) * ... * 1/(1-1/p^z)   
n: All natural numbers
z = a+bi, a != 1
p = All prime numbers

ln(Zeta(z)) = -[ln(1-1/2^z)+ln(1-1/3^z)+ln(1-1/5^z)+ln(1-1/7^z)+...+ln(1-1/p^z)]
                 = x
Zeta(z) = e^x

150 years ago, no computer, the great mathematicians used their pens to calculate the Zeta(z) Nontrivial zeros. That's a very difficult job. Admiring!

The problem with the previous images was due to the step value being too large.
now it works fine.
Say you, Say me, Say the codes together for ever.

guga

#10
Hi Six_L you´re welcome.

Now, try this. (Added zoom with mouse wheel and pg up/down), also it starts (resets) with a space and not only the R key

// ZetaVisualizerFinal.c - Added Page Up/Page Down zoom, smoothed curve, fixed starting line
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <objidl.h>
#include <gdiplus.h>
#include <math.h>
#include <stdio.h>
#include <time.h>
#include <commdlg.h>
#include <vector>

#pragma comment(lib, "gdiplus.lib")
#pragma comment(lib, "user32.lib")
#pragma comment(lib, "gdi32.lib")

using namespace Gdiplus;

// Global variables for animation and zoom
static float animationProgress = 0.0f; // 0.0 to 1.0
static const float ANIMATION_SPEED = 0.005f; // Adjust for faster/slower animation
static const UINT_PTR ANIMATION_TIMER_ID = 1;
static bool isAnimationRunning = false; // Track animation state
static float zoomFactor = 1.0f; // Zoom factor (1.0 = default, >1 zoom in, <1 zoom out)

// Complex number structure
typedef struct {
    double real;
    double imag;
} Complex;

// Complex arithmetic functions
Complex ComplexAdd(Complex a, Complex b) {
    Complex result;
    result.real = a.real + b.real;
    result.imag = a.imag + b.imag;
    return result;
}

Complex ComplexMul(Complex a, Complex b) {
    Complex result;
    result.real = a.real * b.real - a.imag * b.imag;
    result.imag = a.real * b.imag + a.imag * b.real;
    return result;
}

Complex ComplexSub(Complex a, Complex b) {
    Complex result;
    result.real = a.real - b.real;
    result.imag = a.imag - b.imag;
    return result;
}

Complex ComplexPowReal(Complex base, double exponent) {
    double r = sqrt(base.real * base.real + base.imag * base.imag);
    double theta = atan2(base.imag, base.real);
    double ln_r = log(r);
    double exponent_ln_r = exponent * ln_r;
    double exponent_theta = exponent * theta;
    Complex result;
    result.real = exp(exponent_ln_r) * cos(exponent_theta);
    result.imag = exp(exponent_ln_r) * sin(exponent_theta);
    return result;
}

Complex ComplexPow(Complex base, Complex exponent) {
    double r = sqrt(base.real * base.real + base.imag * base.imag);
    double theta = atan2(base.imag, base.real);
    Complex ln_base;
    ln_base.real = log(r);
    ln_base.imag = theta;
    Complex exponent_ln_base = ComplexMul(exponent, ln_base);
    double magnitude = exp(exponent_ln_base.real);
    Complex result;
    result.real = magnitude * cos(exponent_ln_base.imag);
    result.imag = magnitude * sin(exponent_ln_base.imag);
    return result;
}

Complex ComplexDiv(Complex a, Complex b) {
    double denom = b.real * b.real + b.imag * b.imag;
    Complex result;
    result.real = (a.real * b.real + a.imag * b.imag) / denom;
    result.imag = (a.imag * b.real - a.real * b.imag) / denom;
    return result;
}

Complex ComplexScale(Complex a, double scalar) {
    Complex result;
    result.real = a.real * scalar;
    result.imag = a.imag * scalar;
    return result;
}

Complex ComplexNeg(Complex a) {
    Complex result;
    result.real = -a.real;
    result.imag = -a.imag;
    return result;
}

// Complex logarithm: ln(z) = ln(|z|) + i * arg(z)
Complex ComplexLn(Complex z) {
    Complex result;
    result.real = log(sqrt(z.real * z.real + z.imag * z.imag));
    result.imag = atan2(z.imag, z.real);
    return result;
}

// Generate prime numbers using Sieve of Eratosthenes
std::vector<int> GeneratePrimes(int limit) {
    std::vector<bool> isPrime(limit + 1, true);
    isPrime[0] = isPrime[1] = false;
    for (int i = 2; i * i <= limit; i++) {
        if (isPrime[i]) {
            for (int j = i * i; j <= limit; j += i) {
                isPrime[j] = false;
            }
        }
    }

    std::vector<int> primes;
    for (int i = 2; i <= limit; i++) {
        if (isPrime[i]) {
            primes.push_back(i);
        }
    }
    return primes;
}

// Zeta function using Euler product: ζ(z) = exp(-∑_p ln(1 - p^(-z)))
Complex Zeta(Complex z, int iterations) {
    static std::vector<int> primes;
    if (primes.empty()) {
        primes = GeneratePrimes(1000);
    }

    Complex sum = { 0.0, 0.0 };
    Complex one = { 1.0, 0.0 };
    Complex p_complex, p_neg_z, term;

    int count = 0;
    for (int p : primes) {
        if (count >= iterations) break;
        p_complex.real = (double)p;
        p_complex.imag = 0.0;

        Complex neg_z = ComplexNeg(z);
        p_neg_z = ComplexPow(p_complex, neg_z);
        term = ComplexSub(one, p_neg_z);
        Complex ln_term = ComplexLn(term);
        sum = ComplexAdd(sum, ComplexNeg(ln_term));
        count++;
    }

    double magnitude = exp(sum.real);
    Complex result;
    result.real = magnitude * cos(sum.imag);
    result.imag = magnitude * sin(sum.imag);
    return result;
}

// Draw the enhanced Zeta function visualization
void DrawEnhancedZeta(HDC hdc, int width, int height, float progress) {
    Graphics graphics(hdc);
    graphics.SetSmoothingMode(SmoothingModeAntiAlias);
    graphics.SetCompositingQuality(CompositingQualityHighQuality);
    graphics.SetTextRenderingHint(TextRenderingHintAntiAlias);

    // Dark gradient background
    LinearGradientBrush background(
        Point(0, 0),
        Point(width, height),
        Color(255, 10, 20, 50),
        Color(255, 0, 0, 0));
    graphics.FillRectangle(&background, 0, 0, width, height);

    // Set up coordinate system
    REAL centerX = width / 2.0f;
    REAL centerY = height / 2.0f;
    REAL scale = (REAL)min(width, height) / 4.0f;
    REAL unitScale = (scale / 12.0f) * zoomFactor; // Adjusted with zoom factor

    // Draw subtle grid lines (step of 4 units)
    Pen gridPen(Color(50, 100, 100, 150), 0.3f);
    // Horizontal axis: Im(ζ(s)), up to ±32
    for (int i = -8; i <= 8; i++) { // ±32, step 4
        REAL gridPos = i * 4 * unitScale;
        graphics.DrawLine(&gridPen,
            0.0f, centerY + gridPos,
            (REAL)width, centerY + gridPos);
    }
    // Vertical axis: Re(ζ(s)), up to ±24
    for (int i = -6; i <= 6; i++) { // ±24, step 4
        REAL gridPos = i * 4 * unitScale;
        graphics.DrawLine(&gridPen,
            centerX + gridPos, 0.0f,
            centerX + gridPos, (REAL)height);
    }

    // Draw glowing axes
    LinearGradientBrush axisBrush(
        Point(0, (int)centerY),
        Point(width, (int)centerY),
        Color(150, 200, 200, 255),
        Color(50, 100, 100, 100));
    Pen axisPen(&axisBrush, 1.8f);
    graphics.DrawLine(&axisPen, 0.0f, centerY, (REAL)width, centerY);
    graphics.DrawLine(&axisPen, centerX, 0.0f, centerX, (REAL)height);

    // Draw critical line
    LinearGradientBrush criticalBrush(
        Point((int)centerX, 0),
        Point((int)centerX, height),
        Color(150, 255, 150, 50),
        Color(50, 100, 255, 50));
    Pen criticalPen(&criticalBrush, 2.0f);
    REAL criticalX = centerX + scale * 0.5f;
    graphics.DrawLine(&criticalPen, criticalX, 0.0f, criticalX, (REAL)height);

    // Compute Zeta function points and store them
    const int iterations = 200;
    const double t_start = 0.0;
    const double t_end = 30.0;
    const double t_step = 0.02;
    double t_max = t_start + progress * (t_end - t_start);

    // Collect points for the curve
    std::vector<PointF> points;
    for (double t = t_start; t <= t_max; t += t_step) {
        Complex s = { 0.5, t };
        Complex zeta = Zeta(s, iterations);

        REAL x = centerX + (REAL)zeta.imag * unitScale;
        REAL y = centerY - (REAL)zeta.real * unitScale;
        points.push_back(PointF(x, y));
    }

    // Draw the Zeta curve as a smooth spline
    GraphicsPath path;
    if (!points.empty()) {
        path.AddCurve(points.data(), (INT)points.size(), 0.5f); // Tension = 0.5 for smoothness
    }

    // Neon gradient for Zeta curve
    Color colors[] = {
        Color(200, 255, 50, 50),
        Color(200, 255, 165, 0),
        Color(200, 255, 0, 255),
        Color(200, 50, 50, 255)
    };
    REAL positions[] = { 0.0f, 0.33f, 0.67f, 1.0f };
    LinearGradientBrush pathBrush(
        Point(0, (int)(centerY - scale)),
        Point(0, (int)(centerY + scale)),
        Color(255, 255, 255, 255),
        Color(255, 255, 255, 255));
    pathBrush.SetInterpolationColors(colors, positions, 4);

    // Draw glow and main curve
    Pen glowPen(&pathBrush, 5.0f);
    glowPen.SetColor(Color(100, 255, 255, 255));
    graphics.DrawPath(&glowPen, &path);
    Pen zetaPen(&pathBrush, 2.5f);
    graphics.DrawPath(&zetaPen, &path);

    // Add annotations with adjusted positions
    Font font(L"Cambria Math", 16, FontStyleBold);
    Font smallFont(L"Cambria Math", 12, FontStyleRegular);
    SolidBrush shadowBrush(Color(80, 0, 0, 0));
    SolidBrush textBrush(Color(255, 230, 230, 230));
    StringFormat format;
    format.SetAlignment(StringAlignmentCenter);

    // Title: "ζ(s) where s = ½ + ti"
    Font bigFont(L"Cambria Math", 20, FontStyleBold);
    graphics.DrawString(L"ζ(s) where s = ½ + ti", -1, &bigFont,
        PointF(centerX + 4.0f, 24.0f), &format, &shadowBrush);
    graphics.DrawString(L"ζ(s) where s = ½ + ti", -1, &bigFont,
        PointF(centerX, 20.0f), &format, &textBrush);

    // Critical line label: "Re(s) = ½"
    graphics.DrawString(L"Re(s) = ½", -1, &font,
        PointF(criticalX + 4.0f, 60.0f), &format, &shadowBrush);
    graphics.DrawString(L"Re(s) = ½", -1, &font,
        PointF(criticalX, 56.0f), &format, &textBrush);

    // Axis label: "Im(ζ(s))"
    REAL imLabelX = (REAL)width - 100.0f;
    graphics.DrawString(L"Im(ζ(s))", -1, &font,
        PointF(imLabelX + 4.0f, centerY - 24.0f), &shadowBrush);
    graphics.DrawString(L"Im(ζ(s))", -1, &font,
        PointF(imLabelX, centerY - 20.0f), &textBrush);

    // Axis label: "Re(ζ(s))"
    graphics.DrawString(L"Re(ζ(s))", -1, &font,
        PointF(centerX + 14.0f, (REAL)height - 44.0f), &shadowBrush);
    graphics.DrawString(L"Re(ζ(s))", -1, &font,
        PointF(centerX + 10.0f, (REAL)height - 40.0f), &textBrush);

    // Coordinate labels for horizontal axis (Im(ζ(s))): -32 to 32, step 4
    for (int i = -8; i <= 8; i++) {
        int value = i * 4;
        REAL xPos = centerX + value * unitScale;
        WCHAR label[16];
        swprintf(label, 16, L"%d", value);
        graphics.DrawString(label, -1, &smallFont,
            PointF(xPos + 2.0f, centerY + 16.0f), &format, &shadowBrush);
        graphics.DrawString(label, -1, &smallFont,
            PointF(xPos, centerY + 12.0f), &format, &textBrush);
    }

    // Coordinate labels for vertical axis (Re(ζ(s))): -24 to 24, step 4
    StringFormat nearFormat;
    nearFormat.SetAlignment(StringAlignmentNear);
    for (int i = -6; i <= 6; i++) {
        int value = i * 4;
        REAL yPos = centerY - value * unitScale;
        WCHAR label[16];
        if (value == 0) {
            swprintf(label, 16, L"0");
        }
        else {
            swprintf(label, 16, L"%di", value);
        }
        graphics.DrawString(label, -1, &smallFont,
            PointF(centerX - 30.0f + 2.0f, yPos + 2.0f), &nearFormat, &shadowBrush);
        graphics.DrawString(label, -1, &smallFont,
            PointF(centerX - 30.0f, yPos), &nearFormat, &textBrush);
    }

    // Add animated non-trivial zero markers
    double zeros[] = { 14.1347, 21.0220, 25.0109, 30.4249 };
    int numZeros = sizeof(zeros) / sizeof(zeros[0]);
    for (int i = 0; i < numZeros; i++) {
        if (zeros[i] <= t_max) {
            Complex s = { 0.5, zeros[i] };
            Complex zeta = Zeta(s, iterations);
            REAL x = centerX + (REAL)zeta.imag * unitScale;
            REAL y = centerY - (REAL)zeta.real * unitScale;

            LinearGradientBrush zeroBrush(
                Point((int)(x - 10.0f), (int)(y - 10.0f)),
                Point((int)(x + 10.0f), (int)(y + 10.0f)),
                Color(200, 255, 100, 100),
                Color(0, 255, 255, 255));
            graphics.FillEllipse(&zeroBrush, x - 7.0f, y - 7.0f, 14.0f, 14.0f);

            Pen zeroPen(Color(150, 255, 255, 255), 1.0f);
            graphics.DrawEllipse(&zeroPen, x - 7.0f, y - 7.0f, 14.0f, 14.0f);
        }
    }
}

// Helper function to get PNG encoder CLSID
int GetEncoderClsid(const WCHAR* format, CLSID* pClsid) {
    UINT num = 0, size = 0;
    Gdiplus::GetImageEncodersSize(&num, &size);
    if (size == 0) return -1;

    ImageCodecInfo* pImageCodecInfo = (ImageCodecInfo*)(malloc(size));
    Gdiplus::GetImageEncoders(num, size, pImageCodecInfo);

    for (UINT j = 0; j < num; ++j) {
        if (wcscmp(pImageCodecInfo[j].MimeType, format) == 0) {
            *pClsid = pImageCodecInfo[j].Clsid;
            free(pImageCodecInfo);
            return j;
        }
    }

    free(pImageCodecInfo);
    return -1;
}

// Save visualization as PNG
void SaveAsPng(HWND hWnd, int width, int height, const WCHAR* filename) {
    Bitmap bitmap(width, height, PixelFormat32bppARGB);
    Graphics bitmapGraphics(&bitmap);
    bitmapGraphics.SetSmoothingMode(SmoothingModeAntiAlias);
    bitmapGraphics.SetCompositingQuality(CompositingQualityHighQuality);
    bitmapGraphics.SetTextRenderingHint(TextRenderingHintAntiAlias);

    HDC hdc = bitmapGraphics.GetHDC();
    DrawEnhancedZeta(hdc, width, height, 1.0f);
    bitmapGraphics.ReleaseHDC(hdc);

    CLSID clsid;
    if (GetEncoderClsid(L"image/png", &clsid) != -1) {
        bitmap.Save(filename, &clsid, NULL);
        char msg[512];
        snprintf(msg, sizeof(msg), "Visualization saved as %S", filename);
        MessageBoxA(hWnd, msg, "Success", MB_OK | MB_ICONINFORMATION);
    }
    else {
        MessageBoxA(hWnd, "Failed to save PNG: PNG encoder not found", "Error", MB_OK | MB_ICONERROR);
    }
}

// Open file dialog for saving PNG
void ShowSaveDialog(HWND hWnd, int width, int height) {
    WCHAR filename[MAX_PATH] = L"ZetaVisualization.png";
    OPENFILENAMEW ofn = { 0 };
    ofn.lStructSize = sizeof(OPENFILENAMEW);
    ofn.hwndOwner = hWnd;
    ofn.lpstrFilter = L"PNG Files (*.png)\0*.png\0All Files (*.*)\0*.*\0";
    ofn.lpstrFile = filename;
    ofn.nMaxFile = MAX_PATH;
    ofn.lpstrDefExt = L"png";
    ofn.Flags = OFN_OVERWRITEPROMPT | OFN_PATHMUSTEXIST;

    if (GetSaveFileNameW(&ofn)) {
        SaveAsPng(hWnd, width, height, filename);
    }
}

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
    static int width, height;

    switch (message) {
    case WM_CREATE:
        break;

    case WM_TIMER:
        if (wParam == ANIMATION_TIMER_ID) {
            animationProgress += ANIMATION_SPEED;
            if (animationProgress > 1.0f) {
                animationProgress = 1.0f;
                KillTimer(hWnd, ANIMATION_TIMER_ID);
                isAnimationRunning = false;
            }
            InvalidateRect(hWnd, NULL, FALSE);
        }
        break;

    case WM_PAINT: {
        PAINTSTRUCT ps;
        HDC hdc = BeginPaint(hWnd, &ps);

        RECT rect;
        GetClientRect(hWnd, &rect);
        width = rect.right;
        height = rect.bottom;

        HDC memDC = CreateCompatibleDC(hdc);
        HBITMAP memBitmap = CreateCompatibleBitmap(hdc, width, height);
        HBITMAP oldBitmap = (HBITMAP)SelectObject(memDC, memBitmap);

        HBRUSH blackBrush = (HBRUSH)GetStockObject(BLACK_BRUSH);
        FillRect(memDC, &rect, blackBrush);

        DrawEnhancedZeta(memDC, width, height, animationProgress);

        BitBlt(hdc, 0, 0, width, height, memDC, 0, 0, SRCCOPY);

        SelectObject(memDC, oldBitmap);
        DeleteObject(memBitmap);
        DeleteDC(memDC);

        EndPaint(hWnd, &ps);
        break;
    }
    case WM_SIZE:
        width = LOWORD(lParam);
        height = HIWORD(lParam);
        InvalidateRect(hWnd, NULL, TRUE);
        break;

    case WM_MOUSEWHEEL: {
        short delta = GET_WHEEL_DELTA_WPARAM(wParam);
        float zoomStep = 1.1f;

        if (delta > 0) {
            // Scroll up: Zoom in
            zoomFactor *= zoomStep;
            if (zoomFactor > 3.0f) zoomFactor = 3.0f;
        }
        else if (delta < 0) {
            // Scroll down: Zoom out
            zoomFactor /= zoomStep;
            if (zoomFactor < 0.5f) zoomFactor = 0.5f;
        }

        InvalidateRect(hWnd, NULL, FALSE);
        break;
    }

    case WM_COMMAND:
        switch (LOWORD(wParam)) {
        case 1001:
            ShowSaveDialog(hWnd, width, height);
            break;
        case 1002:
            if (!isAnimationRunning) {
                SetTimer(hWnd, ANIMATION_TIMER_ID, 16, NULL);
                isAnimationRunning = true;
            }
            break;
        case 1003:
            if (isAnimationRunning) {
                KillTimer(hWnd, ANIMATION_TIMER_ID);
                isAnimationRunning = false;
            }
            break;
        }
        break;

    case WM_KEYDOWN:
        switch (wParam) {
        case 'R': // Reset animation
        case VK_SPACE: // Also reset with Space key
            animationProgress = 0.0f;
            if (!isAnimationRunning) {
                SetTimer(hWnd, ANIMATION_TIMER_ID, 16, NULL);
                isAnimationRunning = true;
            }
            InvalidateRect(hWnd, NULL, FALSE);
            break;

        case VK_PRIOR: // Page Up: Zoom in
            zoomFactor *= 1.1f;
            if (zoomFactor > 3.0f) zoomFactor = 3.0f;
            InvalidateRect(hWnd, NULL, FALSE);
            break;

        case VK_NEXT: // Page Down: Zoom out
            zoomFactor /= 1.1f;
            if (zoomFactor < 0.5f) zoomFactor = 0.5f;
            InvalidateRect(hWnd, NULL, FALSE);
            break;
        }
        break;

    case WM_DESTROY:
        if (isAnimationRunning) {
            KillTimer(hWnd, ANIMATION_TIMER_ID);
        }
        PostQuitMessage(0);
        break;

    default:
        return DefWindowProcA(hWnd, message, wParam, lParam);
    }
    return 0;
}

int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
    GdiplusStartupInput gdiplusStartupInput;
    ULONG_PTR gdiplusToken;
    GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);

    HMENU hMenu = CreateMenu();
    HMENU hFileMenu = CreatePopupMenu();
    AppendMenuA(hFileMenu, MF_STRING, 1001, "Save As...");
    AppendMenuA(hFileMenu, MF_STRING, 1002, "Start Animation");
    AppendMenuA(hFileMenu, MF_STRING, 1003, "Pause Animation");
    AppendMenuA(hMenu, MF_POPUP, (UINT_PTR)hFileMenu, "File");

    WNDCLASSA wc = { 0 };
    wc.lpfnWndProc = WndProc;
    wc.hInstance = hInstance;
    wc.lpszClassName = "ZetaVisualizer";
    wc.hCursor = LoadCursorA(NULL, IDC_ARROW);
    wc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
    RegisterClassA(&wc);

    HWND hWnd = CreateWindowA("ZetaVisualizer", "Riemann Zeta Function Visualizer",
        WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT,
        1200, 900, NULL, hMenu, hInstance, NULL);

    ShowWindow(hWnd, nCmdShow);
    UpdateWindow(hWnd);

    MSG msg;
    while (GetMessageA(&msg, NULL, 0, 0)) {
        TranslateMessage(&msg);
        DispatchMessageA(&msg);
    }

    DestroyMenu(hMenu);
    GdiplusShutdown(gdiplusToken);
    return (int)msg.wParam;
}


Full project on this link: https://www.mediafire.com/file/kbwfvysh83cc33x/Zeta14.rar/file




Coding in Assembly requires a mix of:
80% of brain, passion, intuition, creativity
10% of programming skills
10% of alcoholic levels in your blood.

My Code Sites:
http://rosasm.freeforums.org
http://winasm.tripod.com

six_L

Hi,guga
good works!
:thumbsup:
I want to compare your image. Could you post an image of the following parameters?

step = 0.012
a = 1/2,b = [-1025.4712,-1015.1512]
Scale = 50:1
iterations = 860

Thank you in advance.

Regards
six_L
Say you, Say me, Say the codes together for ever.

TimoVJL

A test project for pure C with Pelles C.
Just for testing those functions, no graphics.
May the source be with you