Heroes / Esempi / mandelbrot

examples/mandelbrot/

Un programma che conta le iterazioni per calcolare l’insieme di Mandelbrot, con più thread.

Ogni thread, una parte del programma che può lavorare in parallelo, calcola una fascia di righe. Le fasce richiedono quantità di lavoro diverse: per un punto interno all’insieme il calcolo raggiunge il limite di iterazioni, mentre per un punto esterno può fermarsi prima.

Eseguilo

$ heroes run examples/mandelbrot/main.hero
iterations over a 64 by 64 picture: 125957

exit 0 · 1 riga

Il programma

# How many iterations a band of the Mandelbrot set needs, counted by several
# threads — the two-dimensional member of this family.
#
# The band is a range of ROWS, so a thread's index picks a horizontal strip of
# the picture and it works out its own coordinates from that. Nothing about the
# picture crosses the boundary: not the strip, not the pixels, only the total
# number of iterations the strip took, which is one `i64`.
#
# THE ARITHMETIC IS FIXED POINT AND NOT FLOATING, on purpose. This program's
# output is compared byte for byte against `main.expected` on three machines,
# and while IEEE 754 is deterministic, an integer answer needs no argument
# about it at all. The scale is 1000, so a coordinate is a thousandth: the
# picture is coarse and the count is exact, which is the right trade for a
# program whose job is to be checkable rather than pretty.

extern "hero_os.h"
    function hero_thread_spawn(body: (function(i64) -> i64), arg: i64) -> i64
    function hero_thread_join(handle: i64) -> i64

constant SCALE: i64
    1000

constant ROWS: i64
    64

constant COLS: i64
    64

constant LIMIT: i64
    100

# The escape count for one point, in fixed point. `z = z*z + c` with the
# products divided back down by the scale after each multiply.
function escapes_at(cx: i64, cy: i64) -> i64
    zx: i64 @= 0
    zy: i64 @= 0
    n: i64 @= 0

    while n < LIMIT
        xx = zx * zx / SCALE
        yy = zy * zy / SCALE

        if xx + yy > 4 * SCALE
            return n
        nx = xx - yy + cx
        zy @ 2 * zx * zy / SCALE + cy
        zx @ nx
        n @ n + 1

    return LIMIT

# One row of the picture: how many iterations that whole row took.
function row_total(row: i64) -> i64
    total: i64 @= 0
    cy = row * 2 * SCALE / ROWS - SCALE
    col: i64 @= 0

    while col < COLS
        cx = col * 3 * SCALE / COLS - 2 * SCALE
        total @ total + escapes_at(cx: cx, cy: cy)
        col @ col + 1

    return total

# A band is eight rows, and the index picks which eight.
function band(index: i64) -> i64
    total: i64 @= 0
    row: i64 @= index * 8

    while row < index * 8 + 8
        total @ total + row_total(row: row)
        row @ row + 1

    return total

function together() -> i64
    handles: [i64] @= []
    i: i64 @= 0

    while i < ROWS / 8
        handles @ handles.push(hero_thread_spawn(body: band, arg: i))
        i @ i + 1

    total: i64 @= 0

    for h in handles
        total @ total + hero_thread_join(handle: h)

    return total

function alone() -> i64
    total: i64 @= 0
    row: i64 @= 0

    while row < ROWS
        total @ total + row_total(row: row)
        row @ row + 1

    return total

function main()
    print("iterations over a ", COLS, " by ", ROWS, " picture: ", together())

test "the bands agree with the whole picture"
    assert together() == alone()

test "the origin never escapes, because zero is in the set"
    assert escapes_at(cx: 0, cy: 0) == LIMIT

test "a point far to the right escapes at once"
    assert escapes_at(cx: 3 * SCALE, cy: 0) < 5

test "a band is eight rows and no more"
    assert band(index: 0) == row_total(row: 0) + row_total(row: 1) + row_total(row: 2) + row_total(row: 3) + row_total(row: 4) + row_total(row: 5) + row_total(row: 6) + row_total(row: 7)
examples/mandelbrot/main.hero, 114 righe

impronta sha256 5b865a4b1644 · 2 file · index.json

Successivo: matmul. Tutti gli esempi. ← Precedente: threads

Eseguine uno: i quattro comandi. Impara il linguaggio, oppure leggi la specifica completa in un solo file.