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 Today at 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 Today at 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