Return Styles: Pseud0ch, Terminal, Valhalla, NES, Geocities, Blue Moon.

Pages: 1-

ITT we optimize fizzbuzz

Name: Anonymous 2009-05-24 0:16

Here's a pretty basic version in NASM style x86 assembly on linux:
; Fizzbuzz in nasm Linux x86 Assembler

; Prints a natural number onto stdout
%macro    printnumber 1
    pushad

    ; initializations in case of witchcraft
    mov    eax, %1
    mov    ebx, 10
    xor    ecx, ecx

    ; puts digits of number onto stack with first on top
    generate:
    cmp    eax, 0
    je    print
    xor    edx, edx
    div    ebx
    push     edx
    inc    ecx
    jmp    generate
   
    ; pulls digits out of stack and prints them
    print:
    pop     edx
    push     ecx
    ; potential optimization: figure out how to print immediate numbers?
    mov    eax, 4
    mov    ebx, 1
    mov    ecx, numbers
    add    ecx, edx
    mov    edx, 1
    int    0x80
    pop     ecx
    loop print

    ; linebreak
    mov    eax, 4
    mov    ebx, 1
    mov    ecx, linebreak
    mov    edx, 1
    int     0x80

    popad
%endmacro

SECTION .data
fizz:
    db "fizz",10
buzz:
    db "buzz",10
fizzbuzz:
    db "fizzbuzz",10
numbers:
    db "0123456789",10
linebreak:
    db 10

SECTION .text
GLOBAL _start
_start:
    ; initialize loop
    mov    ecx, 1

    mainloop:
    ; check for modulo 3
    mov    ebx, 3
    mov    eax, ecx
    xor    edx, edx
    div    ebx
    cmp    edx, 0
    je    d31

    ; check for modulo 5 if not modulo 3
    mov    ebx, 5
    mov    eax, ecx
    xor    edx, edx
    div    ebx
    cmp    edx, 0
    je     buzzget
   
    ; print number if not modulo 3 or 5
    printnumber ecx
    jmp    loopcheck

    ; how do i long jump///////
    d31:
    jmp d3

    ; modulo 5 not 3 print buzz
    buzzget:
    push    ecx
    mov    eax, 4
    mov    ebx, 1
    mov    ecx, buzz
    mov    edx, 5
    int     0x80
    pop    ecx
    jmp    loopcheck

    ; check for modulo 5 if modulo 3
    d3:
    mov    ebx, 5
    mov    eax, ecx
    xor    edx, edx
    div    ebx
    cmp    edx, 0
    je    fizzbuzzget

    ; modulo 3 not 5 print fizz
    fizzget:
    push    ecx
    mov    eax, 4
    mov    ebx, 1
    mov    ecx, fizz
    mov    edx, 5
    int     0x80
    pop    ecx
    jmp    loopcheck

    ; modulo 3 and 5 print fizzbuzz
    fizzbuzzget:
    push    ecx
    mov    eax, 4
    mov    ebx, 1
    mov    ecx, fizzbuzz
    mov    edx, 9
    int     0x80
    pop    ecx

    ; loop check
    loopcheck:
    inc    ecx
    cmp    ecx, 101
    jne     mainloop

    ; terminate
    mov    eax, 1
    xor    ebx, ebx
    int    0x80


More cycles can certainly be squeezed out of this.
Is there any better way to print numbers than my horrid Θ(log10n) macro?

Name: Anonymous 2009-05-24 0:29

What's the bet a naïve version written in Sepples runs faster?

Name: Anonymous 2009-05-24 0:39

#include <iostream>
using namespace std;

int main (int argc, char ** argv) {
    int i;
    for (i = 1; i < 101; i++) {
        if (i%3==0 && i%5==0) {
            cout << "fizzbuzz\n";
        } else if (i%3==0) {
            cout << "fizz\n";
        } else if (i%5==0) {
            cout << "buzz\n";
        } else {
            cout << i << "\n";
        }
    }
    return 0;
}

compiled with -O3 runs consistently about .004s real, .002s user, .002s sys

>>1 runs consistently about .001s real, .000s user, .001s sys.

That's not the point though, it's hand optimizing assembly for the sake of hand optimizing assembly.

Name: Anonymous 2009-05-24 0:57

Hand-optimising assembly when your algorithm is retarded is kind of like trying to put out a forest fire by peeing on it.

Name: Anonymous 2009-05-24 1:25

>>4
Get in the BUFFA, please.

Name: Anonymous 2009-05-24 1:28

>>4
This is true.  It is also irrelevant--dividing by radix repeated to obtain the individual digits* is the fastest way to convert an integer to a string without using a lookup table.

*this division can be substituted with a faster series of instructions, see Integer division by a constant in http://www.agner.org/optimize/optimizing_assembly.pdf

Name: Anonymous 2009-05-24 1:34

#include <stdio.h>

main () {
    int i;
    for (i = 1; i <= 100; ++i) {
        register short j = 0;
        if (i % 3 == 0 && ++j)
            printf("fizz");
        if (i % 5 == 0 && ++j)
            printf("buzz");
        if (!j)
            printf("%d", i);
        putchar('\n');
    }
}


This is the naïve version (in C, not Sepples), not your bogoversion with its excessive modulo operations.
On my machine, it's four times as fast as your Sepples one and about as fast as your assembly one.

Name: Anonymous 2009-05-24 1:38

>>7
You forgot the %3 part of the problem

Name: Anonymous 2009-05-24 1:39

naïve version
in C
register short j = 0;
putchar
++j
naïve version

No, no, it isn't.  You're doing the equivalent of lovingly hand-crafting zomg optimized assembly code but in the portable assembly that is C.
get out.

Name: Anonymous 2009-05-24 1:40

mapM_ (putStrLn . ap ((`ap` (flip map [3, 5] . (. flip (enumFromThenTo 0) 14) . elem)) . flip ((.) . flip if'  "FizzBuzz" . (0 ==)) . ap (flip if'  "Fizz" . head) . flip (flip if'  "Buzz" . (!! 1)) . show) (flip mod 15)) [1..100]

Name: Anonymous 2009-05-24 1:42

>>8
Did not.

>>9
It's the naïve version of the algorithm, if not necessarily the implementation.

Name: Anonymous 2009-05-24 1:47

>>9
register doesn't mean what you think it means, and code using putchar is far from optimized.

Name: Anonymous 2009-05-24 1:48

>>9
register doesn't tend to do shit, putchar isn't actually faster than printf used on a constant string, and using j++ instead of ++j would break it. There's no zomg optimizing there, just sensible codan.

Name: Anonymous 2009-05-24 1:56

register is the same as please in INTERCAL except the compiler pretend to care

Name: Anonymous 2009-05-24 1:59

>>12
>>13
register is definitely ZOMG OPTIMIZATION. I mean, come on, optimization is the whole goddamn point of the keyword! There's no other reason to use it!

Name: Anonymous 2009-05-24 2:00

(changing register to int)
diff fizzbuzz1.s fizzbuzz2.s
1c1
<      .file     "fizzbuzz1.c"
---
     .file     "fizzbuzz2.c"

lawl

Name: Anonymous 2009-05-24 2:01

>>15
I'll bet anything you like removing the register keyword produces the exact same assembly as with it in there. Register exists for backwards compatability and nothing more.

Name: Anonymous 2009-05-24 2:03

>>16
You changed the register short to simply int? Why would you do that?

Name: Anonymous 2009-05-24 2:06

>>18
To demonstrate that it doesn't do shit to the resulting assembly code.  Have you been following the discussion?

Name: Anonymous 2009-05-24 2:10

>>19
Let me put emphasis on that
register short
short
to
int

There is no way that produces the same assembly code.

Name: Anonymous 2009-05-24 2:13

>>20
From >>16
(changing register to int)
i.e. int short.

you're correct, changing register short to int changes the length of the register used

Name: Anonymous 2009-05-24 2:44

let us shoot some mimes and drink apple juice

Name: Anonymous 2009-05-24 3:11

tell that to auto

what was the point of auto again?

Name: Anonymous 2009-05-24 3:58

"fizzbuzz" < fíðbüþzs {
fíðbüþzs ->
    stef(;)
    staðvær i,j
    stofn
        fyrir(i := 0; i <= 100; i := \stækka i) lykkja
            j := 0,
            ef i % 3 = 0 þá
                skrifastreng(;"fizz"),
                j := 1
            eflok,
            ef i % 5 = 0 þá
                skrifastreng(;"buzz"),
                j := 1
            eflok,
            ef j = 0 þá
                skrifafjöl(;i)
            eflok
        lykkjulok
    stofnlok
}
*
"GRUNNUR"
;

Name: Anonymous 2009-05-24 4:07

>>24
I love you. You're missing a nýlína(;) though.

Will you help me build my Fjölnir compiler?

Name: Anonymous 2009-05-24 4:33

>>25
Sure, but I've just today been figuring out the basic syntax and compiler/linker operation.  Maybe we could grab a wiki and try to document it first.

Name: Anonymous 2009-05-24 4:57

>>16
32-bit gcc 4.3.2
OMG flags: -O3

Using int instead of register short
diff -U2 fizzbuzz.s fizzbuzz_int.s
--- fizzbuzz.s    2009-05-24 10:48:13.000000000 +0200
+++ fizzbuzz_int.s    2009-05-24 10:48:19.000000000 +0200
@@ -1,3 +1,3 @@
-    .file    "fizzbuzz.c"
+    .file    "fizzbuzz_int.c"
     .section    .rodata.str1.1,"aMS",@progbits,1
 .LC0:
@@ -64,5 +64,5 @@
     .p2align 3
 .L4:
-    testw    %cx, %cx
+    testl    %ecx, %ecx
     jne    .L5
     movl    %ebx, 4(%esp)


Using uint_fast8_t instead of short
diff -U2 fizzbuzz.s fizzbuzz_omg.s

--- fizzbuzz.s    2009-05-24 10:48:13.000000000 +0200
+++ fizzbuzz_omg.s    2009-05-24 10:48:17.000000000 +0200
@@ -1,3 +1,3 @@
-    .file    "fizzbuzz.c"
+    .file    "fizzbuzz_omg.c"
     .section    .rodata.str1.1,"aMS",@progbits,1
 .LC0:
@@ -64,5 +64,5 @@
     .p2align 3
 .L4:
-    testw    %cx, %cx
+    testb    %cl, %cl
     jne    .L5
     movl    %ebx, 4(%esp)


Results: In both cases register doesn't do shit.

Name: Anonymous 2009-05-24 6:17

#include <stdio.h>

int main() {
    puts("1\n\
2\n\
fizz\n\
4\n\
buzz\n\
fizz\n\
7\n\
8\n\
fizz\n\
buzz\n\
11\n\
fizz\n\
13\n\
14\n\
fizzbuzz\n\
16\n\
17\n\
fizz\n\
19\n\
buzz\n\
fizz\n\
22\n\
23\n\
fizz\n\
buzz\n\
26\n\
fizz\n\
28\n\
29\n\
fizzbuzz\n\
31\n\
32\n\
fizz\n\
34\n\
buzz\n\
fizz\n\
37\n\
38\n\
fizz\n\
buzz\n\
41\n\
fizz\n\
43\n\
44\n\
fizzbuzz\n\
46\n\
47\n\
fizz\n\
49\n\
buzz\n\
fizz\n\
52\n\
53\n\
fizz\n\
buzz\n\
56\n\
fizz\n\
58\n\
59\n\
fizzbuzz\n\
61\n\
62\n\
fizz\n\
64\n\
buzz\n\
fizz\n\
67\n\
68\n\
fizz\n\
buzz\n\
71\n\
fizz\n\
73\n\
74\n\
fizzbuzz\n\
76\n\
77\n\
fizz\n\
79\n\
buzz\n\
fizz\n\
82\n\
83\n\
fizz\n\
buzz\n\
86\n\
fizz\n\
88\n\
89\n\
fizzbuzz\n\
91\n\
92\n\
fizz\n\
94\n\
buzz\n\
fizz\n\
97\n\
98\n\
fizz\n\
buzz");
    return 0;
}

Name: Anonymous 2009-05-24 15:10

>>26
I'm in, too. I've been wanting to write an EXPERT OPTIMIZING FJÖLNIR COMPILER for a while now, but I don't understand Icelandic.

Name: Anonymous 2009-05-24 15:17

>>28
FV Quality!

Name: ​​​​​​​​​​ 2010-10-25 7:39

Name: Anonymous 2011-01-31 20:21

<-- check em dubz

Don't change these.
Name: Email:
Entire Thread Thread List