Hlavní navigace

Převody zdrojových kódů z jazyka C do jazyka Go

15. 11. 2022
Doba čtení: 52 minut

Sdílet

 Autor: Depositphotos
Seznámíme se s poněkud neobvyklým, ovšem potenciálně velmi užitečným projektem. Tento projekt se jmenuje c4go a jak již jeho název může napovědět, jedná se o nástroj určený k převodům (transpřekladu) zdrojových kódů napsaných původně v jazyku C do jazyka Go.

Obsah

1. Převody zdrojových kódů z jazyka C do jazyka Go

2. Instalace transpřekladače c4go, příprava projektového souboru

3. Program typu „Hello world“ v C s jeho překladem do jazyka Go

4. Program psaný v C, jenž pracuje s řetězci

5. Transpilace zdrojového kódu do Go

6. Program psaný v C, jenž modifikuje řetězce

7. Transpilace zdrojového kódu do Go

8. Algoritmus CORDIC implementovaný v jazyku C

9. Automatická transpilace programu do Go

10. Ruční oprava některých chyb vzniklých při transpilaci

11. Porovnání výsledků: originální C program a opravený program napsaný v Go

12. Složitější program v C: výpočty algoritmu CORDIC ve fixed point aritmetice

13. Automatická transpilace programu do jazyka Go

14. Ruční oprava některých chyb vzniklých při transpilaci

15. Porovnání výsledků výpočtů

16. Program psaný v C, který vytváří a manipuluje se stromovou datovou strukturou

17. Výsledek transpilace programu do jazyka Go

18. Závěrečné zhodnocení

19. Repositář s demonstračními příklady

20. Odkazy na Internetu

1. Převody zdrojových kódů z jazyka C do jazyka Go

V dnešním článku se seznámíme s poněkud neobvyklým, ovšem potenciálně velmi užitečným projektem. Tento projekt se jmenuje c4go a jak již jeho název může napovědět, jedná se o nástroj, který je určený k převodům (transpřekladu) zdrojových kódů napsaných původně v jazyku C do jazyka Go. V úvodní větě jsem napsal, že se jedná o poněkud neobvyklý projekt. Je tomu tak z toho důvodu, že existuje takřka nepřeberné množství transpřekladačů provádějících převody do jazyka C a nikoli naopak (to je logické, protože C je v tomto kontextu chápáno jako „přenositelný assembler“ se všemi z toho plynoucími výhodami a nevýhodami). Proč však provádět opačný překlad? V C je napsáno a především odladěno velké množství algoritmů, knihoven (například knihoven pro GUI) atd. A v některých případech může být výhodné mít tyto zdrojové kódy k dispozici i pro jazyk Go, a to v „nativní“ podobě (tedy nikoli tak, že se jedná o nějaké rozhraní volající nativní céčkový kód).

Poznámka: důležité je, že c4go se musí vypořádat s odlišnostmi mezi C a Go, například v kontextu řetězců, které jsou v Go neměnitelné a současně se s nimi může pracovat jako se sekvencí bajtů nebo se sekvencí run. Ostatně uvidíme v dalším textu, do jaké míry je c4go úspěšný.

2. Instalace transpřekladače c4go, příprava projektového souboru

Instalace transpřekladače c4go je snadná. Nejdříve si ovšem připravíme adresář s projektovým souborem, z něhož posléze příkaz pro instalaci spustíme:

$ mkdir c4go-test
 
$ cd c4go-test
 
$ go mod init c4go-test
go: creating new go.mod: module c4go-test

Dále stáhneme balíček s c4go stáhneme, včetně všech pomocných balíčků:

$ go get -u github.com/Konstantin8105/c4go
 
go: downloading github.com/Konstantin8105/errors v0.0.0-20190517083224-0667bfd7a9ac
go: downloading github.com/Konstantin8105/errors v0.1.0
go: downloading github.com/Konstantin8105/tree v0.0.0-20190515202740-8a8e3df34a3b
go: downloading github.com/Konstantin8105/tree v0.1.0
go: added github.com/Konstantin8105/c4go v0.0.0-20211115111653-1c67b1543446
go: added github.com/Konstantin8105/errors v0.1.0
go: added github.com/Konstantin8105/tree v0.1.0

Nainstalujeme spustitelný transpřekladač, nastavíme cestu a otestuje, zda je překladač nalezen systémem (resp. shellem):

$ go install github.com/Konstantin8105/c4go
 
$ export PATH=~/go/bin:$PATH
 
$ whereis c4go
c4go: /tester/go/bin/c4go

Nakonec otestujeme, jestli je možné transpřekladač skutečně spustit:

$ c4go

Měly by se zobrazit tyto řádky:

Usage: c4go [<command>] [<flags>] file1.c ...
 
Commands:
  transpile     transpile an input C source file or files to Go
  ast           print AST before translated Go code
  debug         add debug information in C source
  version       print version of c4go
  unused        show and action for unused functions

3. Program typu „Hello world“ v C s jeho překladem do jazyka Go

Transpřekladač si nejprve otestujeme na triviálním programu – na čem jiném, než na programu typu „Hello world“, jehož céčková podoba může vypadat následovně:

#include <stdio.h>
 
int main(void)
{
    puts("Hello world");
    return 0;
}
Poznámka: zdrojový kód tohoto prográmku naleznete na adrese https://github.com/tisnik/go-root/blob/master/article97/hello.c.

Transpřeklad se spustí příkazem:

$ c4go transpile hello.c

V případě, že se zobrazí následující chybové hlášení, je nutné doinstalovat i balíček clang:

Error: error in function Start: preprocess error : preprocess for file: [hello.c]
failed: exec: "clang": executable file not found in $PATH
StdErr =

Pokud se žádné chybové hlášení nezobrazí, měl by vypadat výsledek transpřekladu následovně:

//
//      Package - transpiled by c4go
//
//      If you have found any issues, please raise an issue at:
//      https://github.com/Konstantin8105/c4go/
//
 
package main
 
import "github.com/Konstantin8105/c4go/noarch"
 
// main - transpiled function from  /root/c4go-test/hello.c:3
func main() {
        noarch.Puts([]byte("Hello world!\x00"))
        return
}

Povšimněte si volání funkce Puts z balíčku noarch, reprezentace řetězce řezem bajtů, ale i toho, že konec řetězce (ukončující nula) je explicitně zapsán, aby se výsledek co nejvíce podobal céčkovému vzoru.

Poznámka: zdrojový kód transpilovaného programu naleznete na adrese https://github.com/tisnik/go-root/blob/master/article97/hello.go.

4. Program psaný v C, jenž pracuje s řetězci

Podívejme se nyní na jednoduchý program zapsaný v jazyku C, jenž pracuje s řetězci. Jedná se o triviální program, který napřed alokuje paměť pro řetězec, následně do alokovaného bloku překopíruje první slovo a k němu připojí slovo druhé. Výsledný řetězec je posléze vypsán na standardní výstup:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
 
int main(void) {
        char *s = (char*)malloc(100*sizeof(char));
 
        strcpy(s, "Hello ");
        strcat(s, "world!");
        puts(s);
 
        free(s);

}
Poznámka: zdrojový kód tohoto prográmku naleznete na adrese https://github.com/tisnik/go-root/blob/master/article97/strin­gs1.c.

5. Automatická transpilace programu do Go

Po transpilaci zdrojového kódu z předchozí kapitoly získáme tento kód reprezentovaný v Go:

//
//      Package - transpiled by c4go
//
//      If you have found any issues, please raise an issue at:
//      https://github.com/Konstantin8105/c4go/
//
 
package main
 
import "github.com/Konstantin8105/c4go/noarch"
 
// main - transpiled function from  /root/strings.c:5
func main() {
        defer noarch.AtexitRun()
        var s []byte = make([]byte, 100*uint32(1))
        noarch.Strcpy(s, []byte("Hello \x00"))
        noarch.Strcat(s, []byte("world!\x00"))
        noarch.Puts(s)
        _ = s
}

Povšimněte si, že alokace paměti pro „řetězec“ je realizována vytvořením řezu, jenž ovšem obsahuje 100 bajtů (nenechte se zmást převodem konstanty na uint32, skutečně se jedná o sto bajtů – a nikoli o sto znaků z pohledu jazyka Go). Následně můžeme vidět volání funkcí z balíčku noarch i to, že se explicitně pracuje s nulou na konci řetězce.

Poznámka: zdrojový kód transpilovaného programu naleznete na adrese https://github.com/tisnik/go-root/blob/master/article97/strin­gs1.go.

6. Program psaný v C, jenž modifikuje řetězce

Předchozí program nyní nepatrně upravíme, a to konkrétně takovým způsobem, aby byl obsah řetězce programově modifikován. Modifikace (mutation) řetězce je operace, kterou lze v jazyce C bez problémů provést, ovšem v jazyce Go to není možné, protože řetězce zde nejsou modifikovatelné. To však (jak ostatně uvidíme v další kapitole) nevadí, protože c4go generuje kód pracující s řezy a nikoli s řetězci jazyka Go:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
 
int main(void) {
        char *s = (char*)malloc(100*sizeof(char));
 
        strcpy(s, "Hello*");
        strcat(s, "world!");
        puts(s);
 
        s[5] = ' ';
        puts(s);
 
        free(s);

}

Výsledkem by po překladu a spuštění tohoto programu měla být opět zpráva „Hello world!“, protože hvězdička je nahrazena za mezeru.

Poznámka: zdrojový kód tohoto prográmku naleznete na adrese https://github.com/tisnik/go-root/blob/master/article97/strin­gs2.c.

7. Transpilace zdrojového kódu do Go

Céčkový program popsaný v rámci předchozí kapitoly se transpřeloží (pěkné slovo, že) do následující podoby:

//
//      Package - transpiled by c4go
//
//      If you have found any issues, please raise an issue at:
//      https://github.com/Konstantin8105/c4go/
//
 
package main
 
import "github.com/Konstantin8105/c4go/noarch"
 
// main - transpiled function from  /root/strings2.c:5
func main() {
        defer noarch.AtexitRun()
        var s []byte = make([]byte, 100*uint32(1))
        noarch.Strcpy(s, []byte("Hello*\x00"))
        noarch.Strcat(s, []byte("world!\x00"))
        noarch.Puts(s)
        s[5] = ' '
        noarch.Puts(s)
        _ = s
}

Vzhledem k tomu, že se nepracuje přímo s řetězci, ale s řezy (hodnot typu uint32), bylo možné přímo zapsat příkaz:

s[5] = ' '

Zápis ' ' přitom v jazyce Go reprezentuje runu s kódem (hodnotou) 32. Samotná runa je přitom obecně datovým typem rune, který je aliasem pro typ int32. Výše uvedené přiřazení runy do řezu bajtů bude plně funkční pouze za předpokladu, že uvnitř jednoduchých uvozovek bude použit jen ASCII znak, nikoli jiný znak. Tento možná poněkud matoucí koncept jednoznakových literálů je popsán na této stránce.

Poznámka: zdrojový kód transpilovaného programu naleznete na adrese https://github.com/tisnik/go-root/blob/master/article97/strin­gs2.go.

8. Algoritmus CORDIC implementovaný v jazyku C

Další program vytvořený v jazyku C, který budeme převádět do jazyka Go, je již poněkud složitější. Jedná se konkrétně o implementaci výpočtů goniometrických funkcí sinus a kosinus s využitím známého iteračního algoritmu CORDIC (Coordinate Rotation DIgital Computer). Výpočty jsou v tomto konkrétním případě realizovány s numerickými hodnotami typu double, takže převodem do Go otestujeme, jak dobře či špatně se převádí numerické výpočty, operace s poli, programové smyčky, předávání parametrů odkazem (referencí) atd.:

// --------------------------------------------------------
// Výpočet hodnot funkcí sin() a cos() pomocí iteračního
// algoritmu CORDIC.
// --------------------------------------------------------
 
#include <stdio.h>
#include <math.h>
 
#ifndef M_PI
#define M_PI 3.14159265358979323846
#endif
 
// maximální počet iterací při běhu algoritmu
#define MAX_ITER 10
 
// "zesílení" při rotacích
#define K 0.6073
 
// tabulka arkustangentu úhlů
double atans[MAX_ITER];
 
// tabulka záporných celočíselných mocnin hodnoty 2
double pows[MAX_ITER];
 
// naplnění tabulek atans[] a pows[]
void createTables(void)
{
    int i;
    for (i = 0; i < MAX_ITER; i++) {
        double p = pow(2.0, -i);
        atans[i] = atan(p);
        pows[i] = p;
    }
}
 
// výpočet funkcí sin() a cos() pro zadaný úhel delta
void sincos(double delta, double *sinval, double *cosval)
{
    int i;
    double x0 = 1.0;            // nastavení počátečních podmínek
    double y0 = 0.0;
    double xn;
    for (i = 0; i < MAX_ITER; i++) {    // iterační smyčka
        if (delta < 0) {        // úhel je záporný => rotace doleva
            xn = x0 + y0 * pows[i];
            y0 -= x0 * pows[i];
            delta += atans[i];
        } else {                // úhel je kladný => rotace doprava
            xn = x0 - y0 * pows[i];
            y0 += x0 * pows[i];
            delta -= atans[i];
        }
        x0 = xn;
    }
    *sinval = y0 * K;           // opravit "zesílení" výsledku
    *cosval = x0 * K;
}
 
int main(void)
{
    int i;
    createTables();
    for (i = 0; i <= 90; i++) { // výpočetní smyčka
        double delta;           // úhel, ze kterého se počítá sin a cos
        double sinval;          // vypočtené hodnoty
        double cosval;
        double sinerr;          // absolutní chyby
        double coserr;
        delta = i * M_PI / 180.0;       // převod úhlu na radiány
        sincos(delta, &sinval, &cosval);        // výpočet sinu a kosinu
        sinerr = fabs(sinval - sin(delta));     // výpočet absolutních chyb
        coserr = fabs(cosval - cos(delta));
        // tisk výsledků
        printf
            ("%02d\t%12.10f\t%12.10f\t%12.10f\t%12.10f\t%8.3f%%\t%8.3f%%\n",
             i, sinval, cosval, sinerr, coserr, 100.0 * sinerr / sinval,
             100.0 * coserr / cosval);
    }
    return 0;
}
 
// finito
Poznámka: zdrojový kód realizace algoritmu CORDIC naleznete na adrese https://github.com/tisnik/go-root/blob/master/article97/fp.c.

9. Automatická transpilace programu do Go

Po transpilaci programu, jehož zdrojový kód byl ukázán v předchozí kapitole, vznikne kód v jazyce Go, který je možné přeložit a spustit, ale který obsahuje poznámky o interních problémech nalezených transpřekladačem c4go:

//
//      Package - transpiled by c4go
//
//      If you have found any issues, please raise an issue at:
//      https://github.com/Konstantin8105/c4go/
//
 
/* AST Error :
unknown node type: `value: Int 0`
*/
/* AST Error :
unknown node type: `value: Int 1`
*/
/* AST Error :
unknown node type: `value: Int 2`
*/
/* AST Error :
unknown node type: `value: Int 3`
*/
/* AST Error :
unknown node type: `value: Int 4`
*/
/* AST Error :
unknown node type: `value: Int 0`
*/
/* AST Error :
unknown node type: `value: Int 1`
*/
/* AST Error :
unknown node type: `value: Int 2`
*/
/* AST Error :
unknown node type: `value: Int 3`
*/
/* AST Error :
unknown node type: `value: Int 4`
*/
 
package main
 
import "github.com/Konstantin8105/c4go/noarch"
import "unsafe"
import "math"
 
// atans - transpiled function from  /root/fp.c:20
// --------------------------------------------------------
// Výpočet hodnot funkcí sin() a cos() pomocí iteračního
// algoritmu CORDIC.
// --------------------------------------------------------
// maximální počet iterací při běhu algoritmu
// "zesílení" při rotacích
// tabulka arkustangentu úhlů
var /* AST Error :
unknown node type: `value: Int 0`
*/ /* AST Error :
unknown node type: `value: Int 1`
*/ /* AST Error :
unknown node type: `value: Int 2`
*/ /* AST Error :
unknown node type: `value: Int 3`
*/ /* AST Error :
unknown node type: `value: Int 4`
*/ /* AST Error :
unknown node type: `value: Int 0`
*/ /* AST Error :
unknown node type: `value: Int 1`
*/ /* AST Error :
unknown node type: `value: Int 2`
*/ /* AST Error :
unknown node type: `value: Int 3`
*/ /* AST Error :
unknown node type: `value: Int 4`
*/atans []float64 = make([]float64, 10)
 
// pows - transpiled function from  /root/fp.c:23
// tabulka záporných celočíselných mocnin hodnoty 2
var pows []float64 = make([]float64, 10)
 
// createTables - transpiled function from  /root/fp.c:26
func createTables() {
        // naplnění tabulek atans[] a pows[]
        var i int32
        for i = 0; i < 10; i++ {
                var p float64 = math.Pow(2, float64(-i))
                atans[i] = math.Atan(p)
                pows[i] = p
        }
}
 
// sincos - transpiled function from  /root/fp.c:37
func sincos(delta float64, sinval []float64, cosval []float64) {
        // výpočet funkcí sin() a cos() pro zadaný úhel delta
        var i int32
        // nastavení počátečních podmínek
        var x0 float64 = 1
        var y0 float64
        var xn float64
        {
                // iterační smyčka
                for i = 0; i < 10; i++ {
                        if delta < 0 {
                                // úhel je záporný => rotace doleva
                                xn = x0 + y0*pows[i]
                                y0 -= x0 * pows[i]
                                delta += atans[i]
                        } else {
                                // úhel je kladný => rotace doprava
                                xn = x0 - y0*pows[i]
                                y0 += x0 * pows[i]
                                delta -= atans[i]
                        }
                        x0 = xn
                }
        }
        // opravit "zesílení" výsledku
        sinval[0] = y0 * 0.6073
        cosval[0] = x0 * 0.6073
}
 
// main - transpiled function from  /root/fp.c:59
func main() {
        var i int32
        createTables()
        {
                // výpočetní smyčka
                for i = 0; i <= 90; i++ {
                        // úhel, ze kterého se počítá sin a cos
                        var delta float64
                        // vypočtené hodnoty
                        var sinval float64
                        var cosval float64
                        // absolutní chyby
                        var sinerr float64
                        var coserr float64
                        // převod úhlu na radiány
                        delta = float64(i) * 3.141592653589793 / 180
                        // výpočet sinu a kosinu
                        sincos(delta, c4goUnsafeConvert_float64(&sinval), c4goUnsafeConvert_float64(&cosval))
                        // výpočet absolutních chyb
                        sinerr = math.Abs(sinval - math.Sin(delta))
                        coserr = math.Abs(cosval - math.Cos(delta))
                        // tisk výsledků
                        noarch.Printf([]byte("%02d\t%12.10f\t%12.10f\t%12.10f\t%12.10f\t%8.3f%%\t%8.3f%%\n\x00"), i, sinval, cosval, sinerr, coserr, 100*sinerr/sinval, 100*coserr/cosval)
                }
        }
        return
}
 
// c4goUnsafeConvert_float64 : created by c4go
func c4goUnsafeConvert_float64(c4go_name *float64) []float64 {
        return (*[1000000]float64)(unsafe.Pointer(c4go_name))[:]
}
 
// finito

Povšimněte si toho, že parametry do funkce sincos se nepředávají čistě referencí, ale přes řezy (slice):

func sincos(delta float64, sinval []float64, cosval []float64) {
    ...
    ...
    ...
}

Vytvoření takového řezu je vyřešeno dosti nešťastným způsobem, konkrétně vytvořením beztypového ukazatele (unsafe.Pointer:

// c4goUnsafeConvert_float64 : created by c4go
func c4goUnsafeConvert_float64(c4go_name *float64) []float64 {
        return (*[1000000]float64)(unsafe.Pointer(c4go_name))[:]
}
Poznámka: zdrojový kód transpilovaného programu naleznete na adrese https://github.com/tisnik/go-root/blob/master/article97/fp_tran­spiled.go.

10. Ruční oprava některých chyb vzniklých při transpilaci

Program vzniklý automatickou transpilací je ovšem možné relativně snadno opravit takovým způsobem, aby byl čitelnější, nepoužíval unsafe ukazatele atd. Nejdříve změníme hlavičku funkce sincos z této verze:

func sincos(delta float64, sinval []float64, cosval []float64) {
    ...
    ...
    ...
}

na následující variantu s typovanými ukazateli:

func sincos(delta float64, sinval *float64, cosval *float64) {
    ...
    ...
    ...
}

tuto funkci lze zavolat triviálně, tedy bez použití různých triků a konverzí:

var sinval float64
var cosval float64
 
sincos(delta, &sinval, &cosval)

Dále odstraníme volání funkcí z balíčku noarch a použijeme standardní funkci fmt.Printf. Balíček noarch tedy ani nemusíme importovat:

fmt.Printf("%02d\t%12.10f\t%12.10f\t%12.10f\t%12.10f\t%8.3f%%\t%8.3f%%\n", i, sinval, cosval, sinerr, coserr, 100*sinerr/sinval, 100*coserr/cosval)

Výsledek (po smazání různých varovných komentářů) bude vypadat následovně – jedná se o dobře čitelný Go kód:

package main
 
import "math"
import "fmt"
 
// --------------------------------------------------------
// Výpočet hodnot funkcí sin() a cos() pomocí iteračního
// algoritmu CORDIC.
// --------------------------------------------------------
// maximální počet iterací při běhu algoritmu
// "zesílení" při rotacích
// tabulka arkustangentu úhlů
var atans []float64 = make([]float64, 10)
 
// pows - transpiled function from  /root/fp.c:23
// tabulka záporných celočíselných mocnin hodnoty 2
var pows []float64 = make([]float64, 10)
 
// createTables - transpiled function from  /root/fp.c:26
func createTables() {
        // naplnění tabulek atans[] a pows[]
        var i int32
        for i = 0; i < 10; i++ {
                var p float64 = math.Pow(2, float64(-i))
                atans[i] = math.Atan(p)
                pows[i] = p
        }
}
 
// sincos - transpiled function from  /root/fp.c:37
func sincos(delta float64, sinval *float64, cosval *float64) {
        // výpočet funkcí sin() a cos() pro zadaný úhel delta
        var i int32
        // nastavení počátečních podmínek
        var x0 float64 = 1
        var y0 float64
        var xn float64
        {
                // iterační smyčka
                for i = 0; i < 10; i++ {
                        if delta < 0 {
                                // úhel je záporný => rotace doleva
                                xn = x0 + y0*pows[i]
                                y0 -= x0 * pows[i]
                                delta += atans[i]
                        } else {
                                // úhel je kladný => rotace doprava
                                xn = x0 - y0*pows[i]
                                y0 += x0 * pows[i]
                                delta -= atans[i]
                        }
                        x0 = xn
                }
        }
        // opravit "zesílení" výsledku
        *sinval = y0 * 0.6073
        *cosval = x0 * 0.6073
}
 
// main - transpiled function from  /root/fp.c:59
func main() {
        var i int32
        createTables()
        {
                // výpočetní smyčka
                for i = 0; i <= 90; i++ {
                        // úhel, ze kterého se počítá sin a cos
                        var delta float64
                        // vypočtené hodnoty
                        var sinval float64
                        var cosval float64
                        // absolutní chyby
                        var sinerr float64
                        var coserr float64
                        // převod úhlu na radiány
                        delta = float64(i) * 3.141592653589793 / 180
                        // výpočet sinu a kosinu
                        sincos(delta, &sinval, &cosval)
                        // výpočet absolutních chyb
                        sinerr = math.Abs(sinval - math.Sin(delta))
                        coserr = math.Abs(cosval - math.Cos(delta))
                        // tisk výsledků
                        fmt.Printf("%02d\t%12.10f\t%12.10f\t%12.10f\t%12.10f\t%8.3f%%\t%8.3f%%\n", i, sinval, cosval, sinerr, coserr, 100*sinerr/sinval, 100*coserr/cosval)
                }
        }
        return
}
 
// finito
Poznámka: zdrojový kód takto upraveného programu naleznete na adrese https://github.com/tisnik/go-root/blob/master/article97/fp_co­rrected.go.

Rozdíl mezi transpilovaným kódem a ručně upraveným kódem:

--- fp_transpiled.go    2022-11-08 17:38:33.000000000 +0100
+++ fp_corrected.go     2022-11-12 14:37:22.383210131 +0100
@@ -1,46 +1,7 @@
-//
-//     Package - transpiled by c4go
-//
-//     If you have found any issues, please raise an issue at:
-//     https://github.com/Konstantin8105/c4go/
-//
-
-/* AST Error :
-unknown node type: `value: Int 0`
-*/
-/* AST Error :
-unknown node type: `value: Int 1`
-*/
-/* AST Error :
-unknown node type: `value: Int 2`
-*/
-/* AST Error :
-unknown node type: `value: Int 3`
-*/
-/* AST Error :
-unknown node type: `value: Int 4`
-*/
-/* AST Error :
-unknown node type: `value: Int 0`
-*/
-/* AST Error :
-unknown node type: `value: Int 1`
-*/
-/* AST Error :
-unknown node type: `value: Int 2`
-*/
-/* AST Error :
-unknown node type: `value: Int 3`
-*/
-/* AST Error :
-unknown node type: `value: Int 4`
-*/
-
 package main
 
-import "github.com/Konstantin8105/c4go/noarch"
-import "unsafe"
 import "math"
+import "fmt"
 
 // atans - transpiled function from  /root/fp.c:20
 // --------------------------------------------------------
@@ -50,27 +11,7 @@
 // maximální počet iterací při běhu algoritmu
 // "zesílení" při rotacích
 // tabulka arkustangentu úhlů
-var /* AST Error :
-unknown node type: `value: Int 0`
-*/ /* AST Error :
-unknown node type: `value: Int 1`
-*/ /* AST Error :
-unknown node type: `value: Int 2`
-*/ /* AST Error :
-unknown node type: `value: Int 3`
-*/ /* AST Error :
-unknown node type: `value: Int 4`
-*/ /* AST Error :
-unknown node type: `value: Int 0`
-*/ /* AST Error :
-unknown node type: `value: Int 1`
-*/ /* AST Error :
-unknown node type: `value: Int 2`
-*/ /* AST Error :
-unknown node type: `value: Int 3`
-*/ /* AST Error :
-unknown node type: `value: Int 4`
-*/atans []float64 = make([]float64, 10)
+var atans []float64 = make([]float64, 10)
 
 // pows - transpiled function from  /root/fp.c:23
 // tabulka záporných celočíselných mocnin hodnoty 2
@@ -88,7 +29,7 @@
 }
 
 // sincos - transpiled function from  /root/fp.c:37
-func sincos(delta float64, sinval []float64, cosval []float64) {
+func sincos(delta float64, sinval *float64, cosval *float64) {
        // výpočet funkcí sin() a cos() pro zadaný úhel delta
        var i int32
        // nastavení počátečních podmínek
@@ -113,8 +54,8 @@
                }
        }
        // opravit "zesílení" výsledku
-       sinval[0] = y0 * 0.6073
-       cosval[0] = x0 * 0.6073
+       *sinval = y0 * 0.6073
+       *cosval = x0 * 0.6073
 }
 
 // main - transpiled function from  /root/fp.c:59
@@ -135,20 +76,15 @@
                        // převod úhlu na radiány
                        delta = float64(i) * 3.141592653589793 / 180
                        // výpočet sinu a kosinu
-                       sincos(delta, c4goUnsafeConvert_float64(&sinval), c4goUnsafeConvert_float64(&cosval))
+                       sincos(delta, &sinval, &cosval)
                        // výpočet absolutních chyb
                        sinerr = math.Abs(sinval - math.Sin(delta))
                        coserr = math.Abs(cosval - math.Cos(delta))
                        // tisk výsledků
-                       noarch.Printf([]byte("%02d\t%12.10f\t%12.10f\t%12.10f\t%12.10f\t%8.3f%%\t%8.3f%%\n\x00"), i, sinval, cosval, sinerr, coserr, 100*sinerr/sinval, 100*coserr/cosval)
+                       fmt.Printf("%02d\t%12.10f\t%12.10f\t%12.10f\t%12.10f\t%8.3f%%\t%8.3f%%\n", i, sinval, cosval, sinerr, coserr, 100*sinerr/sinval, 100*coserr/cosval)
                }
        }
        return
 }
 
-// c4goUnsafeConvert_float64 : created by c4go
-func c4goUnsafeConvert_float64(c4go_name *float64) []float64 {
-       return (*[1000000]float64)(unsafe.Pointer(c4go_name))[:]
-}
-
 // finito

11. Porovnání výsledků: originální C program a opravený program napsaný v Go

Oba programy, tj. jak originální program zapsaný v jazyku C, tak i program transpilovaný do jazyka Go, po svém překladu a spuštění zobrazí naprosto shodnou tabulku výsledky, která vypadá takto (hlavičky sloupců jsem pro větší přehled dopsal ručně). Výsledky jsou naprosto totožné až na poslední desetinné místo (což může být u některých algoritmů velmi důležité kritérium):

i       sin(x)          cos(x)          abs.err sin(x)  abs.err cos(x)   rel.err sin(x)  rel.err cos(x)
00      0.0011726802    1.0000761814    0.0011726802    0.0000761814     100.000%          0.008%
01      0.0167806202    0.9999360752    0.0006717863    0.0000883801       4.003%          0.009%
02      0.0363058568    0.9994176447    0.0014063601    0.0000268177       3.874%          0.003%
03      0.0519144682    0.9987285075    0.0004214880    0.0000989728       0.812%          0.010%
04      0.0714093909    0.9975241564    0.0016529171    0.0000398938       2.315%          0.004%
05      0.0858859660    0.9963821278    0.0012697767    0.0001874297       1.478%          0.019%
06      0.1053286152    0.9945147694    0.0008001519    0.0000071260       0.760%          0.001%
07      0.1208522102    0.9927479474    0.0010171332    0.0002017957       0.842%          0.020%
08      0.1401999641    0.9902008452    0.0010268631    0.0000672235       0.732%          0.007%
09      0.1556537948    0.9878894877    0.0007806702    0.0002011471       0.502%          0.020%
10      0.1749154013    0.9846615389    0.0012672237    0.0001462141       0.724%          0.015%
11      0.1902784482    0.9818084619    0.0005305471    0.0001812785       0.279%          0.018%
12      0.2092807371    0.9779342089    0.0013690463    0.0002133919       0.654%          0.022%
13      0.2245344811    0.9745450275    0.0004165732    0.0001749627       0.186%          0.018%
14      0.2435223655    0.9699745364    0.0016004699    0.0003211899       0.657%          0.033%
15      0.2586475676    0.9660513338    0.0001714775    0.0001255075       0.066%          0.013%
16      0.2774481762    0.9608206145    0.0018108204    0.0004410814       0.653%          0.046%
17      0.2924243921    0.9563690285    0.0000526874    0.0000642725       0.018%          0.007%
18      0.3073310520    0.9516834391    0.0016859423    0.0006269228       0.549%          0.066%
19      0.3251452218    0.9457453825    0.0004229326    0.0002268069       0.130%          0.024%
20      0.3435512762    0.9392157709    0.0015311329    0.0004768498       0.446%          0.051%
21      0.3581836921    0.9337334665    0.0001842574    0.0001530400       0.051%          0.016%
22      0.3763350045    0.9265666237    0.0017284111    0.0006172309       0.459%          0.067%
23      0.3907657879    0.9205736488    0.0000346594    0.0000687953       0.009%          0.007%
24      0.4050994316    0.9143567106    0.0016372115    0.0008112530       0.404%          0.089%
25      0.4228792420    0.9062708704    0.0002609802    0.0000369167       0.062%          0.004%
26      0.4368623186    0.8996138385    0.0015088282    0.0008197922       0.345%          0.091%
27      0.4543481744    0.8909104782    0.0003576747    0.0000960460       0.079%          0.011%
28      0.4682106568    0.8837038670    0.0012609060    0.0007562742       0.269%          0.086%
29      0.4853645826    0.8743997745    0.0005549624    0.0002199326       0.114%          0.025%
30      0.4989670003    0.8667096840    0.0010329997    0.0006842803       0.207%          0.079%
31      0.5157967696    0.8568006981    0.0007586947    0.0003666026       0.147%          0.043%
32      0.5291205039    0.8486372819    0.0007987604    0.0005891857       0.151%          0.069%
33      0.5446674419    0.8387437758    0.0000284069    0.0000732079       0.005%          0.009%
34      0.5577055299    0.8301314870    0.0014873735    0.0010939144       0.267%          0.132%
35      0.5738098078    0.8190824429    0.0002333714    0.0000696014       0.041%          0.008%
36      0.5865371490    0.8100172323    0.0012481033    0.0010002379       0.213%          0.123%
37      0.6022307543    0.7984183504    0.0004157312    0.0002171596       0.069%          0.027%
38      0.6146302652    0.7889127841    0.0010312101    0.0009020305       0.168%          0.114%
39      0.6299202599    0.7767587849    0.0005998689    0.0003871766       0.095%          0.050%
40      0.6418729918    0.7669112114    0.0009146178    0.0008667682       0.142%          0.113%
41      0.6567280845    0.7542293861    0.0006690555    0.0004801942       0.102%          0.064%
42      0.6684306187    0.7438778473    0.0006999876    0.0007330218       0.105%          0.099%
43      0.6828308344    0.7306817333    0.0008324743    0.0006719683       0.122%          0.092%
44      0.6941513412    0.7199358716    0.0005070292    0.0005960713       0.073%          0.083%
45      0.7062435465    0.7080775359    0.0008632347    0.0009707547       0.122%          0.137%
46      0.7199358716    0.6941513412    0.0005960713    0.0005070292       0.083%          0.073%
47      0.7306817333    0.6828308344    0.0006719683    0.0008324743       0.092%          0.122%
48      0.7438778473    0.6684306187    0.0007330218    0.0006999876       0.099%          0.105%
49      0.7542293861    0.6567280845    0.0004801942    0.0006690555       0.064%          0.102%
50      0.7669112114    0.6418729918    0.0008667682    0.0009146178       0.113%          0.142%
51      0.7767587849    0.6299202599    0.0003871766    0.0005998689       0.050%          0.095%
52      0.7889127841    0.6146302652    0.0009020305    0.0010312101       0.114%          0.168%
53      0.7984183504    0.6022307543    0.0002171596    0.0004157312       0.027%          0.069%
54      0.8100172323    0.5865371490    0.0010002379    0.0012481033       0.123%          0.213%
55      0.8190824429    0.5738098078    0.0000696014    0.0002333714       0.008%          0.041%
56      0.8301314870    0.5577055299    0.0010939144    0.0014873735       0.132%          0.267%
57      0.8387437758    0.5446674419    0.0000732079    0.0000284069       0.009%          0.005%
58      0.8486372819    0.5291205039    0.0005891857    0.0007987604       0.069%          0.151%
59      0.8568006981    0.5157967696    0.0003666026    0.0007586947       0.043%          0.147%
60      0.8667096840    0.4989670003    0.0006842803    0.0010329997       0.079%          0.207%
61      0.8743997745    0.4853645826    0.0002199326    0.0005549624       0.025%          0.114%
62      0.8837038670    0.4682106568    0.0007562742    0.0012609060       0.086%          0.269%
63      0.8909104782    0.4543481744    0.0000960460    0.0003576747       0.011%          0.079%
64      0.8996138385    0.4368623186    0.0008197922    0.0015088282       0.091%          0.345%
65      0.9062708704    0.4228792420    0.0000369167    0.0002609802       0.004%          0.062%
66      0.9143567106    0.4050994316    0.0008112530    0.0016372115       0.089%          0.404%
67      0.9205736488    0.3907657879    0.0000687953    0.0000346594       0.007%          0.009%
68      0.9265666237    0.3763350045    0.0006172309    0.0017284111       0.067%          0.459%
69      0.9337334665    0.3581836921    0.0001530400    0.0001842574       0.016%          0.051%
70      0.9392157709    0.3435512762    0.0004768498    0.0015311329       0.051%          0.446%
71      0.9457453825    0.3251452218    0.0002268069    0.0004229326       0.024%          0.130%
72      0.9516834391    0.3073310520    0.0006269228    0.0016859423       0.066%          0.549%
73      0.9563690285    0.2924243921    0.0000642725    0.0000526874       0.007%          0.018%
74      0.9608206145    0.2774481762    0.0004410814    0.0018108204       0.046%          0.653%
75      0.9660513338    0.2586475676    0.0001255075    0.0001714775       0.013%          0.066%
76      0.9699745364    0.2435223655    0.0003211899    0.0016004699       0.033%          0.657%
77      0.9745450275    0.2245344811    0.0001749627    0.0004165732       0.018%          0.186%
78      0.9779342089    0.2092807371    0.0002133919    0.0013690463       0.022%          0.654%
79      0.9818084619    0.1902784482    0.0001812785    0.0005305471       0.018%          0.279%
80      0.9846615389    0.1749154013    0.0001462141    0.0012672237       0.015%          0.724%
81      0.9878894877    0.1556537948    0.0002011471    0.0007806702       0.020%          0.502%
82      0.9902008452    0.1401999641    0.0000672235    0.0010268631       0.007%          0.732%
83      0.9927479474    0.1208522102    0.0002017957    0.0010171332       0.020%          0.842%
84      0.9945147694    0.1053286152    0.0000071260    0.0008001519       0.001%          0.760%
85      0.9963821278    0.0858859660    0.0001874297    0.0012697767       0.019%          1.478%
86      0.9975241564    0.0714093909    0.0000398938    0.0016529171       0.004%          2.315%
87      0.9987285075    0.0519144682    0.0000989728    0.0004214880       0.010%          0.812%
88      0.9994176447    0.0363058568    0.0000268177    0.0014063601       0.003%          3.874%
89      0.9999360752    0.0167806202    0.0000883801    0.0006717863       0.009%          4.003%
90      1.0000761814    0.0011726802    0.0000761814    0.0011726802       0.008%        100.000%

12. Složitější program v C: výpočty algoritmu CORDIC ve fixed point aritmetice

Zatímco byl původní program pro výpočet hodnot sinu a kosinu s využitím algoritmu CORDIC založen na výpočtech prováděných s numerickými hodnotami s plovoucí řádovou čárkou (floating point), ukážeme si v této kapitole stejný algoritmus, ovšem upravený tak, aby se výpočty prováděly s numerickými hodnotami s pevnou řádovou čárkou (fixed point), konkrétně s hodnotami, které mají před binární řádovou tečkou šestnáct bitů a za řádovou tečkou taktéž šestnáct bitů (lze ovlivnit konstantami A a B). Otestujeme tedy, jak jsou tyto v mnoha ohledech nízkoúrovňové operace založené na bitových operacích převedeny z jazyka C do jazyka Go (program navíc přímo tiskne tabulku s výsledky v HTML):

#include <stdlib.h>
#include <stdio.h>
#include <math.h>
 
/* počet míst před a za binární řádovou tečkou */
#define A 16
#define B 16
 
/* Ludolfovo číslo */
#ifndef M_PI
#define M_PI 3.14159265358979323846
#endif
 
/* maximální počet iterací při běhu algoritmu */
#define MAX_ITER 16
 
/* "zesílení" při rotacích */
#define K_float 0.6073
 
/* převody mezi stupni a radiány */
#define rad2deg(rad) ((rad)*180.0/M_PI)
#define deg2rad(deg) ((deg)/180.0*M_PI)
 
/* datový typ, se kterým budeme pracovat */
typedef signed int fx;
 
/* hlavičky použitých funkcí */
void fx_print(fx x);
fx fp2fx(double x);
double fx2fp(fx x);
 
/* tabulka arkustangentu úhlů */
fx atans[MAX_ITER];
 
/* tabulka záporných celočíselných mocnin hodnoty 2 */
fx pows[MAX_ITER];
 
/*
 * Tisk numerické hodnoty uložené ve formátu pevné
 * řádové binární čárky (FX)
 */
void fx_print(fx x)
{
    int i;
    int val = x;                /* pomocná proměnná pro převod do dvojkové soustavy */
    printf("bin: ");
    for (i = 0; i < A + B; i++) {       /* převod na řetězec bitů (do dvojkové soustavy) */
        putchar(!!(val & (1 << (A + B - 1))) + '0');    /* výpis hodnoty aktuálně nejvyššího bitu */
        if (i == B - 1)
            putchar('.');       /* po řádové binární čárce vypsat značku */
        val = val << 1;         /* posun na další (méně významný) bit */
    }
 
    printf("   hex: %08x   fp: %+11.5f\n", x, fx2fp(x));
}
 
/*
 * Převod z formátu plovoucí řádové binární čárky (FP)
 * do formátu pevné řádové binární čárky (FX)
 */
fx fp2fx(double x)
{
    return (fx) (x * (2 << (B - 1)));
}
 
/*
 * Převod z celočíselného formátu (integer)
 * do formátu pevné řádové binární čárky (FX)
 */
fx int2fx(int x)
{
    return (fx) (x << B);
}
 
/*
 * Převod z formátu pevné řádové binární čárky (FX)
 * do formátu plovoucí řádové binární čárky (FP)
 */
double fx2fp(fx x)
{
    return (double) x / (2 << (B - 1));
}
 
/*
 * Součet dvou hodnot uložených ve shodném formátu
 * pevné binární řádové čárky (FX)
 */
fx fx_add(fx x, fx y)
{
    return x + y;
}
 
/*
 * Rozdíl dvou hodnot uložených ve shodném formátu
 * pevné binární řádové čárky (FX)
 */
fx fx_sub(fx x, fx y)
{
    return x - y;
}
 
/*
 * Součin dvou hodnot uložených ve shodném formátu
 * pevné binární řádové čárky (FX)
 */
fx fx_mul(fx x, fx y)
{
    fx result = (x >> (B / 2)) * (y >> (B / 2));
    return result;
}
 
/*
 * Podíl dvou hodnot uložených ve shodném formátu
 * pevné binární řádové čárky (FX)
 */
fx fx_div(fx x, fx y)
{
    fx result = x / (y >> (B / 2));
    return result << (B / 2);
}
 
/*
 * Vytvoření tabulky pro výpočet goniometrických
 * funkcí pomocí algoritmu CORDIC
 */
void fx_create_tables(void)
{
    int i;
    for (i = 0; i < MAX_ITER; i++) {
        double p = pow(2.0, -i);
        atans[i] = fp2fx(atan(p));
        pows[i] = fp2fx(p);
    }
}
 
/* výpočet funkce tan() pro zadaný úhel delta */
/* (neoptimalizovaná verze) */
fx fx_tan_cordic(fx delta)
{
    int i;
    /* nastavení počátečních podmínek */
    fx x0 = fp2fx(1.0);
    fx y0 = fp2fx(0.0);
    fx xn;
    if (delta == 0)
        return 0;               /* ošetření nulového úhlu */
    for (i = 0; i < MAX_ITER; i++) {    /* iterační smyčka */
        if (delta < 0) {        /* úhel je záporný => rotace doleva */
            xn = fx_add(x0, fx_mul(y0, pows[i]));
            y0 = fx_sub(y0, fx_mul(x0, pows[i]));
            delta = fx_add(delta, atans[i]);
        } else {                /* úhel je kladný => rotace doprava */
            xn = fx_sub(x0, fx_mul(y0, pows[i]));
            y0 = fx_add(y0, fx_mul(x0, pows[i]));
            delta = fx_sub(delta, atans[i]);
        }
        x0 = xn;
/*        printf("%i\t%+f\t%+f\t%+f\n", i, fx2fp(x0), fx2fp(y0), fx2fp(delta)); */
    }
    if (x0 == 0)                /* ošetření tangenty pravého úhlu */
        if (y0 < 0)
            return 0;
        else
            return 0;
    else
        return fx_div(y0, x0);  /* vrátit výsledek operace */
}
 
/* výpočet funkce tan() pro zadaný úhel delta */
/* (optimalizovaná verze) */
fx fx_tan_cordic_optim(fx delta)
{
    int i;
    /* nastavení počátečních podmínek */
    fx x0 = int2fx(1);
    fx y0 = 0;
    fx xn;
    if (delta == 0)
        return 0;               /* ošetření nulového úhlu */
    for (i = 0; i < MAX_ITER; i++) {    /* iterační smyčka */
        if (delta < 0) {        /* úhel je záporný => rotace doleva */
            xn = fx_add(x0, y0 >> i);   /* místo násobení bitový posuv */
            y0 = fx_sub(y0, x0 >> i);
            delta = fx_add(delta, atans[i]);
        } else {                /* úhel je kladný => rotace doprava */
            xn = fx_sub(x0, y0 >> i);
            y0 = fx_add(y0, x0 >> i);
            delta = fx_sub(delta, atans[i]);
        }
        x0 = xn;
    }
    if (x0 == 0)                /* ošetření tangenty pravého úhlu */
        if (y0 < 0)
            return 0;
        else
            return 0;
    else
        return fx_div(y0, x0);  /* vrátit výsledek operace */
}
 
/* výpočet funkce sin() pro zadaný úhel delta */
fx fx_sin_cordic_optim(fx delta)
{
    int i;
    static fx K_fx = (fx) (K_float * (2 << (B - 1)));
    /* nastavení počátečních podmínek */
    fx x0 = int2fx(1);
    fx y0 = 0;
    fx xn;
    for (i = 0; i < MAX_ITER; i++) {    /* iterační smyčka */
        if (delta < 0) {        /* úhel je záporný => rotace doleva */
            xn = fx_add(x0, y0 >> i);   /* místo násobení bitový posuv */
            y0 = fx_sub(y0, x0 >> i);
            delta = fx_add(delta, atans[i]);
        } else {                /* úhel je kladný => rotace doprava */
            xn = fx_sub(x0, y0 >> i);
            y0 = fx_add(y0, x0 >> i);
            delta = fx_sub(delta, atans[i]);
        }
        x0 = xn;
    }
    return fx_mul(y0, K_fx);    /* opravit "zesílení" výsledku */
}
 
/* výpočet funkce cos() pro zadaný úhel delta */
fx fx_cos_cordic_optim(fx delta)
{
    int i;
    static fx K_fx = (fx) (K_float * (2 << (B - 1)));
    /* nastavení počátečních podmínek */
    fx x0 = int2fx(1);
    fx y0 = 0;
    fx xn;
    for (i = 0; i < MAX_ITER; i++) {    /* iterační smyčka */
        if (delta < 0) {        /* úhel je záporný => rotace doleva */
            xn = fx_add(x0, y0 >> i);   /* místo násobení bitový posuv */
            y0 = fx_sub(y0, x0 >> i);
            delta = fx_add(delta, atans[i]);
        } else {                /* úhel je kladný => rotace doprava */
            xn = fx_sub(x0, y0 >> i);
            y0 = fx_add(y0, x0 >> i);
            delta = fx_sub(delta, atans[i]);
        }
        x0 = xn;
    }
    return fx_mul(x0, K_fx);    /* opravit "zesílení" výsledku */
}
 
/* výpočet funkce sin() pro zadaný úhel delta */
fx fx_sin_cordic_optim_iter(fx delta, int iter)
{
    int i;
    static fx K_fx = (fx) (K_float * (2 << (B - 1)));
    /* nastavení počátečních podmínek */
    fx x0 = int2fx(1);
    fx y0 = 0;
    fx xn;
    for (i = 0; i < iter; i++) {        /* iterační smyčka */
        if (delta < 0) {        /* úhel je záporný => rotace doleva */
            xn = fx_add(x0, y0 >> i);   /* místo násobení bitový posuv */
            y0 = fx_sub(y0, x0 >> i);
            delta = fx_add(delta, atans[i]);
        } else {                /* úhel je kladný => rotace doprava */
            xn = fx_sub(x0, y0 >> i);
            y0 = fx_add(y0, x0 >> i);
            delta = fx_sub(delta, atans[i]);
        }
        x0 = xn;
    }
    return fx_mul(y0, K_fx);    /* opravit "zesílení" výsledku */
}
 
/* výpočet funkce cos() pro zadaný úhel delta */
fx fx_cos_cordic_optim_iter(fx delta, int iter)
{
    int i;
    static fx K_fx = (fx) (K_float * (2 << (B - 1)));
    /* nastavení počátečních podmínek */
    fx x0 = int2fx(1);
    fx y0 = 0;
    fx xn;
    for (i = 0; i < iter; i++) {        /* iterační smyčka */
        if (delta < 0) {        /* úhel je záporný => rotace doleva */
            xn = fx_add(x0, y0 >> i);   /* místo násobení bitový posuv */
            y0 = fx_sub(y0, x0 >> i);
            delta = fx_add(delta, atans[i]);
        } else {                /* úhel je kladný => rotace doprava */
            xn = fx_sub(x0, y0 >> i);
            y0 = fx_add(y0, x0 >> i);
            delta = fx_sub(delta, atans[i]);
        }
        x0 = xn;
    }
    return fx_mul(x0, K_fx);    /* opravit "zesílení" výsledku */
}
 
int main(void)
{
    int i;
    fx cosfx;
    double delta;               /* úhel, ze kterého se funkce počítá */
    double value;               /* vypočtené hodnoty */
    double abs_err;             /* absolutní chyby */
    double rel_err;             /* relativní chyby */
    char *zvyr1, *zvyr2;        /* ukazatele na konstantní řetězce pro */
    /* generování HTML */
 
    fx_create_tables();
 
    puts("\n<h2>Výpočet funkce cos() optimalizovanou metodou CORDIC</h2>\n");
    puts("<table>");
    printf
        ("<tr><th>Úhel</th><th>cos FP</th><th>cos FX</th><th>Abs.chyba</th><th>Rel.chyba</th></tr>\n");
    for (i = 0; i <= 90; i++) { /* výpočetní smyčka */
        delta = deg2rad(i);     /* převod úhlu na radiány */
        cosfx = fx_cos_cordic_optim(fp2fx(delta));      /* aplikace algoritmu CORDIC */
        value = fx2fp(cosfx);   /* výpočet funkce cos */
        abs_err = fabs(value - cos(delta));     /* výpočet absolutních chyb */
        rel_err = cos(delta) <= 1e-10 ? 0 : 100.0 * abs_err / cos(delta);
        if (rel_err <= 1.0) {
            zvyr1 = "<strong>";
            zvyr2 = "</strong>";
        } else {
            zvyr1 = "";
            zvyr2 = "";
        }
        printf
            ("<tr><td>%02d</td><td>%5.3f</td><td>%5.3f%%</td><td>%5.3f</td><td>%s%5.3f%%%s</td></tr>\n",
             i, value, cos(delta), abs_err, zvyr1, rel_err, zvyr2);
    }
    puts("</table>");
    return 0;
}
 
// finito
Poznámka: zdrojový kód tímto způsobem realizovaného algoritmu CORDIC naleznete na adrese https://github.com/tisnik/go-root/blob/master/article97/fx.c.

13. Automatická transpilace programu do jazyka Go

Po transpilaci zdrojového kódu z předchozí kapitoly získáme tento kód reprezentovaný v jazyce Go. Opět si povšimněte několika poznámek s varováním o interních problémech překladače:

//
//      Package - transpiled by c4go
//
//      If you have found any issues, please raise an issue at:
//      https://github.com/Konstantin8105/c4go/
//
 
/* AST Error :
unknown node type: `value: Int 0`
*/
/* AST Error :
unknown node type: `value: Int 1`
*/
/* AST Error :
unknown node type: `value: Int 2`
*/
/* AST Error :
unknown node type: `value: Int 3`
*/
/* AST Error :
unknown node type: `value: Int 4`
*/
/* AST Error :
unknown node type: `value: Int 0`
*/
/* AST Error :
unknown node type: `value: Int 1`
*/
/* AST Error :
unknown node type: `value: Int 2`
*/
/* AST Error :
unknown node type: `value: Int 3`
*/
/* AST Error :
unknown node type: `value: Int 4`
*/
 
package main
 
import "math"
import "github.com/Konstantin8105/c4go/noarch"
import "fmt"
 
// fx - transpiled function from  /root/fx.c:25
// počet míst před a za binární řádovou tečkou
// Ludolfovo číslo
// maximální počet iterací při běhu algoritmu
// "zesílení" při rotacích
// převody mezi stupni a radiány
// datový typ, se kterým budeme pracovat
/* AST Error :
unknown node type: `value: Int 0`
*/ /* AST Error :
unknown node type: `value: Int 1`
*/ /* AST Error :
unknown node type: `value: Int 2`
*/ /* AST Error :
unknown node type: `value: Int 3`
*/ /* AST Error :
unknown node type: `value: Int 4`
*/ /* AST Error :
unknown node type: `value: Int 0`
*/ /* AST Error :
unknown node type: `value: Int 1`
*/ /* AST Error :
unknown node type: `value: Int 2`
*/ /* AST Error :
unknown node type: `value: Int 3`
*/ /* AST Error :
unknown node type: `value: Int 4`
*/type fx = int32
 
// atans - transpiled function from  /root/fx.c:33
// hlavičky použitých funkcí
// tabulka arkustangentu úhlů
var atans []fx = make([]fx, 16)
 
// pows - transpiled function from  /root/fx.c:36
// tabulka záporných celočíselných mocnin hodnoty 2
var pows []fx = make([]fx, 16)
 
// fx_print - transpiled function from  /root/fx.c:42
func fx_print(x fx) {
        //
        // * Tisk numerické hodnoty uložené ve formátu pevné
        // * řádové binární čárky (FX)
        //
        var i int32
        // pomocná proměnná pro převod do dvojkové soustavy
        var val int32 = int32((x))
        fmt.Printf("bin: ")
        {
                // převod na řetězec bitů (do dvojkové soustavy)
                for i = 0; i < 16+16; i++ {
                        // výpis hodnoty aktuálně nejvyššího bitu
                        noarch.Putchar(noarch.BoolToInt(!noarch.Not(val&(1<<uint64(16+16-1)))) + int32('0'))
                        if i == 16-1 {
                                // po řádové binární čárce vypsat značku
                                noarch.Putchar(int32('.'))
                        }
                        // posun na další (méně významný) bit
                        val = val << uint64(1)
                }
        }
        noarch.Printf([]byte("   hex: %08x   fp: %+11.5f\n\x00"), x, fx2fp(x))
}
 
// fp2fx - transpiled function from  /root/fx.c:61
func fp2fx(x float64) fx {
        //
        // * Převod z formátu plovoucí řádové binární čárky (FP)
        // * do formátu pevné řádové binární čárky (FX)
        //
        return fx(x * float64(2<<uint64(16-1)))
}
 
// int2fx - transpiled function from  /root/fx.c:70
func int2fx(x int32) fx {
        //
        // * Převod z celočíselného formátu (integer)
        // * do formátu pevné řádové binární čárky (FX)
        //
        return fx(x << uint64(16))
}
 
// fx2fp - transpiled function from  /root/fx.c:79
func fx2fp(x fx) float64 {
        //
        // * Převod z formátu pevné řádové binární čárky (FX)
        // * do formátu plovoucí řádové binární čárky (FP)
        //
        return float64(int32((x))) / float64(2<<uint64(16-1))
}
 
// fx_add - transpiled function from  /root/fx.c:88
func fx_add(x fx, y fx) fx {
        //
        // * Součet dvou hodnot uložených ve shodném formátu
        // * pevné binární řádové čárky (FX)
        //
        return x + y
}
 
// fx_sub - transpiled function from  /root/fx.c:97
func fx_sub(x fx, y fx) fx {
        //
        // * Rozdíl dvou hodnot uložených ve shodném formátu
        // * pevné binární řádové čárky (FX)
        //
        return x - y
}
 
// fx_mul - transpiled function from  /root/fx.c:106
func fx_mul(x fx, y fx) fx {
        //
        // * Součin dvou hodnot uložených ve shodném formátu
        // * pevné binární řádové čárky (FX)
        //
        var result fx = x >> uint64(16/2) * (y >> uint64(16/2))
        return result
}
 
// fx_div - transpiled function from  /root/fx.c:116
func fx_div(x fx, y fx) fx {
        //
        // * Podíl dvou hodnot uložených ve shodném formátu
        // * pevné binární řádové čárky (FX)
        //
        var result fx = x / (y >> uint64(16/2))
        return result << uint64(16/2)
}
 
// fx_create_tables - transpiled function from  /root/fx.c:126
func fx_create_tables() {
        //
        // * Vytvoření tabulky pro výpočet goniometrických
        // * funkcí pomocí algoritmu CORDIC
        //
        var i int32
        for i = 0; i < 16; i++ {
                var p float64 = math.Pow(2, float64(-i))
                atans[i] = fp2fx(math.Atan(p))
                pows[i] = fp2fx(p)
        }
}
 
// fx_tan_cordic - transpiled function from  /root/fx.c:138
func fx_tan_cordic(delta fx) (c4goDefaultReturn fx) {
        // výpočet funkce tan() pro zadaný úhel delta
        // (neoptimalizovaná verze)
        var i int32
        // nastavení počátečních podmínek
        var x0 fx = fp2fx(1)
        var y0 fx
        var xn fx
        if delta == fx((0)) {
                // ošetření nulového úhlu
                return fx((0))
        }
        {
                // iterační smyčka
                for i = 0; i < 16; i++ {
                        if delta < fx((0)) {
                                // úhel je záporný => rotace doleva
                                xn = fx_add(x0, fx_mul(y0, pows[i]))
                                y0 = fx_sub(y0, fx_mul(x0, pows[i]))
                                delta = fx_add(delta, atans[i])
                        } else {
                                // úhel je kladný => rotace doprava
                                xn = fx_sub(x0, fx_mul(y0, pows[i]))
                                y0 = fx_add(y0, fx_mul(x0, pows[i]))
                                delta = fx_sub(delta, atans[i])
                        }
                        x0 = xn
                }
        }
        if x0 == fx((0)) {
                if y0 < fx((0)) {
                        //        printf("%i\t%+f\t%+f\t%+f\n", i, fx2fp(x0), fx2fp(y0), fx2fp(delta));
                        // ošetření tangenty pravého úhlu
                        return fx((0))
                } else {
                        return fx((0))
                }
        } else {
                // vrátit výsledek operace
                return fx_div(y0, x0)
        }
        return
}
 
// fx_tan_cordic_optim - transpiled function from  /root/fx.c:171
func fx_tan_cordic_optim(delta fx) (c4goDefaultReturn fx) {
        // výpočet funkce tan() pro zadaný úhel delta
        // (optimalizovaná verze)
        var i int32
        // nastavení počátečních podmínek
        var x0 fx = int2fx(1)
        var y0 fx = fx((0))
        var xn fx
        if delta == fx((0)) {
                // ošetření nulového úhlu
                return fx((0))
        }
        {
                // iterační smyčka
                for i = 0; i < 16; i++ {
                        if delta < fx((0)) {
                                // úhel je záporný => rotace doleva
                                // místo násobení bitový posuv
                                xn = fx_add(x0, y0>>uint64(i))
                                y0 = fx_sub(y0, x0>>uint64(i))
                                delta = fx_add(delta, atans[i])
                        } else {
                                // úhel je kladný => rotace doprava
                                xn = fx_sub(x0, y0>>uint64(i))
                                y0 = fx_add(y0, x0>>uint64(i))
                                delta = fx_sub(delta, atans[i])
                        }
                        x0 = xn
                }
        }
        if x0 == fx((0)) {
                if y0 < fx((0)) {
                        // ošetření tangenty pravého úhlu
                        return fx((0))
                } else {
                        return fx((0))
                }
        } else {
                // vrátit výsledek operace
                return fx_div(y0, x0)
        }
        return
}
 
// fx_sin_cordic_optim - transpiled function from  /root/fx.c:202
func fx_sin_cordic_optim(delta fx) fx {
        // výpočet funkce sin() pro zadaný úhel delta
        var i int32
        var K_fx fx = fx(0.6073 * float64(2<<uint64(16-1)))
        // nastavení počátečních podmínek
        var x0 fx = int2fx(1)
        var y0 fx = fx((0))
        var xn fx
        {
                // iterační smyčka
                for i = 0; i < 16; i++ {
                        if delta < fx((0)) {
                                // úhel je záporný => rotace doleva
                                // místo násobení bitový posuv
                                xn = fx_add(x0, y0>>uint64(i))
                                y0 = fx_sub(y0, x0>>uint64(i))
                                delta = fx_add(delta, atans[i])
                        } else {
                                // úhel je kladný => rotace doprava
                                xn = fx_sub(x0, y0>>uint64(i))
                                y0 = fx_add(y0, x0>>uint64(i))
                                delta = fx_sub(delta, atans[i])
                        }
                        x0 = xn
                }
        }
        // opravit "zesílení" výsledku
        return fx_mul(y0, K_fx)
}
 
// fx_cos_cordic_optim - transpiled function from  /root/fx.c:226
func fx_cos_cordic_optim(delta fx) fx {
        // výpočet funkce cos() pro zadaný úhel delta
        var i int32
        var K_fx fx = fx(0.6073 * float64(2<<uint64(16-1)))
        // nastavení počátečních podmínek
        var x0 fx = int2fx(1)
        var y0 fx = fx((0))
        var xn fx
        {
                // iterační smyčka
                for i = 0; i < 16; i++ {
                        if delta < fx((0)) {
                                // úhel je záporný => rotace doleva
                                // místo násobení bitový posuv
                                xn = fx_add(x0, y0>>uint64(i))
                                y0 = fx_sub(y0, x0>>uint64(i))
                                delta = fx_add(delta, atans[i])
                        } else {
                                // úhel je kladný => rotace doprava
                                xn = fx_sub(x0, y0>>uint64(i))
                                y0 = fx_add(y0, x0>>uint64(i))
                                delta = fx_sub(delta, atans[i])
                        }
                        x0 = xn
                }
        }
        // opravit "zesílení" výsledku
        return fx_mul(x0, K_fx)
}
 
// fx_sin_cordic_optim_iter - transpiled function from  /root/fx.c:250
func fx_sin_cordic_optim_iter(delta fx, iter int32) fx {
        // výpočet funkce sin() pro zadaný úhel delta
        var i int32
        var K_fx fx = fx(0.6073 * float64(2<<uint64(16-1)))
        // nastavení počátečních podmínek
        var x0 fx = int2fx(1)
        var y0 fx = fx((0))
        var xn fx
        {
                // iterační smyčka
                for i = 0; i < iter; i++ {
                        if delta < fx((0)) {
                                // úhel je záporný => rotace doleva
                                // místo násobení bitový posuv
                                xn = fx_add(x0, y0>>uint64(i))
                                y0 = fx_sub(y0, x0>>uint64(i))
                                delta = fx_add(delta, atans[i])
                        } else {
                                // úhel je kladný => rotace doprava
                                xn = fx_sub(x0, y0>>uint64(i))
                                y0 = fx_add(y0, x0>>uint64(i))
                                delta = fx_sub(delta, atans[i])
                        }
                        x0 = xn
                }
        }
        // opravit "zesílení" výsledku
        return fx_mul(y0, K_fx)
}
 
// fx_cos_cordic_optim_iter - transpiled function from  /root/fx.c:274
func fx_cos_cordic_optim_iter(delta fx, iter int32) fx {
        // výpočet funkce cos() pro zadaný úhel delta
        var i int32
        var K_fx fx = fx(0.6073 * float64(2<<uint64(16-1)))
        // nastavení počátečních podmínek
        var x0 fx = int2fx(1)
        var y0 fx = fx((0))
        var xn fx
        {
                // iterační smyčka
                for i = 0; i < iter; i++ {
                        if delta < fx((0)) {
                                // úhel je záporný => rotace doleva
                                // místo násobení bitový posuv
                                xn = fx_add(x0, y0>>uint64(i))
                                y0 = fx_sub(y0, x0>>uint64(i))
                                delta = fx_add(delta, atans[i])
                        } else {
                                // úhel je kladný => rotace doprava
                                xn = fx_sub(x0, y0>>uint64(i))
                                y0 = fx_add(y0, x0>>uint64(i))
                                delta = fx_sub(delta, atans[i])
                        }
                        x0 = xn
                }
        }
        // opravit "zesílení" výsledku
        return fx_mul(x0, K_fx)
}
 
// main - transpiled function from  /root/fx.c:297
func main() {
        defer noarch.AtexitRun()
        var i int32
        var cosfx fx
        // úhel, ze kterého se funkce počítá
        var delta float64
        // vypočtené hodnoty
        var value float64
        // absolutní chyby
        var abs_err float64
        // relativní chyby
        var rel_err float64
        // ukazatele na konstantní řetězce pro
        var zvyr1 []byte
        var zvyr2 []byte
        // generování HTML
        fx_create_tables()
        noarch.Puts([]byte("\n<h2>Výpočet funkce cos() optimalizovanou metodou CORDIC</h2>\n\x00"))
        noarch.Puts([]byte("<table>\x00"))
        fmt.Printf("<tr><th>Úhel</th><th>cos FP</th><th>cos FX</th><th>Abs.chyba</th><th>Rel.chyba</th></tr>\n")
        {
                // výpočetní smyčka
                for i = 0; i <= 90; i++ {
                        // převod úhlu na radiány
                        delta = float64(i) / 180 * 3.141592653589793
                        // aplikace algoritmu CORDIC
                        cosfx = fx_cos_cordic_optim(fp2fx(delta))
                        // výpočet funkce cos
                        value = fx2fp(cosfx)
                        // výpočet absolutních chyb
                        abs_err = math.Abs(value - math.Cos(delta))
                        if math.Cos(delta) <= 1e-10 {
                                rel_err = 0
                        } else {
                                rel_err = 100 * abs_err / math.Cos(delta)
                        }
                        if rel_err <= 1 {
                                zvyr1 = []byte("<strong>\x00")
                                zvyr2 = []byte("</strong>\x00")
                        } else {
                                zvyr1 = []byte("\x00")
                                zvyr2 = []byte("\x00")
                        }
                        noarch.Printf([]byte("<tr><td>%02d</td><td>%5.3f</td><td>%5.3f%%</td><td>%5.3f</td><td>%s%5.3f%%%s</td></tr>\n\x00"), i, value, math.Cos(delta), abs_err, zvyr1, rel_err, zvyr2)
                }
        }
        noarch.Puts([]byte("</table>\x00"))
        return
}
 
// finito
Poznámka: zdrojový kód transpilovaného programu naleznete na adrese https://github.com/tisnik/go-root/blob/master/article97/fx_tran­spiled.go.

14. Ruční oprava některých chyb vzniklých při transpilaci

Překlad transpilovaného zdrojového kódu v jeho původní podobně není možný (chyba c4go):

$ go build fx_transpiled.go 
 
# command-line-arguments
./fx_transpiled.go:97:52: (1 << uint64(16 + 16 - 1)) (untyped int constant 2147483648) overflows int32
./fx_transpiled.go:282:19: cannot convert 0.6073 * float64(2 << uint64(16 - 1)) (constant 39800 of type float64) to type int32
./fx_transpiled.go:313:19: cannot convert 0.6073 * float64(2 << uint64(16 - 1)) (constant 39800 of type float64) to type int32
./fx_transpiled.go:344:19: cannot convert 0.6073 * float64(2 << uint64(16 - 1)) (constant 39800 of type float64) to type int32
./fx_transpiled.go:375:19: cannot convert 0.6073 * float64(2 << uint64(16 - 1)) (constant 39800 of type float64) to type int32

Z tohoto důvodu je nutné provést několik úprav s tím, že následující zdrojový kód je již bez problémů jak přeložitelný, tak i spustitelný a navíc poskytne stejné výsledky, jako originální céčkový kód:

var K_fx fx = fx(math.Round(0.6073 * float64(2<<uint64(16-1))))
var K_fx fx = fx(math.Round(0.6073 * float64(2<<uint64(16-1))))
var K_fx fx = fx(math.Round(0.6073 * float64(2<<uint64(16-1))))
var K_fx fx = fx(math.Round(0.6073 * float64(2<<uint64(16-1))))

Výsledek:

package main
 
import "math"
import "github.com/Konstantin8105/c4go/noarch"
import "fmt"
 
type fx int32
 
// atans - transpiled function from  /root/fx.c:33
// hlavičky použitých funkcí
// tabulka arkustangentu úhlů
var atans []fx = make([]fx, 16)
 
// pows - transpiled function from  /root/fx.c:36
// tabulka záporných celočíselných mocnin hodnoty 2
var pows []fx = make([]fx, 16)
 
// fx_print - transpiled function from  /root/fx.c:42
func fx_print(x fx) {
        //
        // * Tisk numerické hodnoty uložené ve formátu pevné
        // * řádové binární čárky (FX)
        //
        var i int32
        // pomocná proměnná pro převod do dvojkové soustavy
        var val uint32 = uint32((x))
        fmt.Printf("bin: ")
        {
                // převod na řetězec bitů (do dvojkové soustavy)
                for i = 0; i < 16+16; i++ {
                        // výpis hodnoty aktuálně nejvyššího bitu
                        bit := val & (1 << (16 + 16 - 1))
                        noarch.Putchar(noarch.BoolToInt(!noarch.Not(bit)) + int32('0'))
                        if i == 16-1 {
                                // po řádové binární čárce vypsat značku
                                noarch.Putchar(int32('.'))
                        }
                        // posun na další (méně významný) bit
                        val = val << uint64(1)
                }
        }
        noarch.Printf([]byte("   hex: %08x   fp: %+11.5f\n\x00"), x, fx2fp(x))
}
 
// fp2fx - transpiled function from  /root/fx.c:61
func fp2fx(x float64) fx {
        //
        // * Převod z formátu plovoucí řádové binární čárky (FP)
        // * do formátu pevné řádové binární čárky (FX)
        //
        return fx(x * float64(2<<uint64(16-1)))
}
 
// int2fx - transpiled function from  /root/fx.c:70
func int2fx(x int32) fx {
        //
        // * Převod z celočíselného formátu (integer)
        // * do formátu pevné řádové binární čárky (FX)
        //
        return fx(x << uint64(16))
}
 
// fx2fp - transpiled function from  /root/fx.c:79
func fx2fp(x fx) float64 {
        //
        // * Převod z formátu pevné řádové binární čárky (FX)
        // * do formátu plovoucí řádové binární čárky (FP)
        //
        return float64(int32((x))) / float64(2<<uint64(16-1))
}
 
// fx_add - transpiled function from  /root/fx.c:88
func fx_add(x fx, y fx) fx {
        //
        // * Součet dvou hodnot uložených ve shodném formátu
        // * pevné binární řádové čárky (FX)
        //
        return x + y
}
 
// fx_sub - transpiled function from  /root/fx.c:97
func fx_sub(x fx, y fx) fx {
        //
        // * Rozdíl dvou hodnot uložených ve shodném formátu
        // * pevné binární řádové čárky (FX)
        //
        return x - y
}
 
// fx_mul - transpiled function from  /root/fx.c:106
func fx_mul(x fx, y fx) fx {
        //
        // * Součin dvou hodnot uložených ve shodném formátu
        // * pevné binární řádové čárky (FX)
        //
        var result fx = x >> uint64(16/2) * (y >> uint64(16/2))
        return result
}
 
// fx_div - transpiled function from  /root/fx.c:116
func fx_div(x fx, y fx) fx {
        //
        // * Podíl dvou hodnot uložených ve shodném formátu
        // * pevné binární řádové čárky (FX)
        //
        var result fx = x / (y >> uint64(16/2))
        return result << uint64(16/2)
}
 
// fx_create_tables - transpiled function from  /root/fx.c:126
func fx_create_tables() {
        //
        // * Vytvoření tabulky pro výpočet goniometrických
        // * funkcí pomocí algoritmu CORDIC
        //
        var i int32
        for i = 0; i < 16; i++ {
                var p float64 = math.Pow(2, float64(-i))
                atans[i] = fp2fx(math.Atan(p))
                pows[i] = fp2fx(p)
        }
}
 
// fx_tan_cordic - transpiled function from  /root/fx.c:138
func fx_tan_cordic(delta fx) (c4goDefaultReturn fx) {
        // výpočet funkce tan() pro zadaný úhel delta
        // (neoptimalizovaná verze)
        var i int32
        // nastavení počátečních podmínek
        var x0 fx = fp2fx(1)
        var y0 fx
        var xn fx
        if delta == fx((0)) {
                // ošetření nulového úhlu
                return fx((0))
        }
        {
                // iterační smyčka
                for i = 0; i < 16; i++ {
                        if delta < fx((0)) {
                                // úhel je záporný => rotace doleva
                                xn = fx_add(x0, fx_mul(y0, pows[i]))
                                y0 = fx_sub(y0, fx_mul(x0, pows[i]))
                                delta = fx_add(delta, atans[i])
                        } else {
                                // úhel je kladný => rotace doprava
                                xn = fx_sub(x0, fx_mul(y0, pows[i]))
                                y0 = fx_add(y0, fx_mul(x0, pows[i]))
                                delta = fx_sub(delta, atans[i])
                        }
                        x0 = xn
                }
        }
        if x0 == fx((0)) {
                if y0 < fx((0)) {
                        //        printf("%i\t%+f\t%+f\t%+f\n", i, fx2fp(x0), fx2fp(y0), fx2fp(delta));
                        // ošetření tangenty pravého úhlu
                        return fx((0))
                } else {
                        return fx((0))
                }
        } else {
                // vrátit výsledek operace
                return fx_div(y0, x0)
        }
        return
}
 
// fx_tan_cordic_optim - transpiled function from  /root/fx.c:171
func fx_tan_cordic_optim(delta fx) (c4goDefaultReturn fx) {
        // výpočet funkce tan() pro zadaný úhel delta
        // (optimalizovaná verze)
        var i int32
        // nastavení počátečních podmínek
        var x0 fx = int2fx(1)
        var y0 fx = fx((0))
        var xn fx
        if delta == fx((0)) {
                // ošetření nulového úhlu
                return fx((0))
        }
        {
                // iterační smyčka
                for i = 0; i < 16; i++ {
                        if delta < fx((0)) {
                                // úhel je záporný => rotace doleva
                                // místo násobení bitový posuv
                                xn = fx_add(x0, y0>>uint64(i))
                                y0 = fx_sub(y0, x0>>uint64(i))
                                delta = fx_add(delta, atans[i])
                        } else {
                                // úhel je kladný => rotace doprava
                                xn = fx_sub(x0, y0>>uint64(i))
                                y0 = fx_add(y0, x0>>uint64(i))
                                delta = fx_sub(delta, atans[i])
                        }
                        x0 = xn
                }
        }
        if x0 == fx((0)) {
                if y0 < fx((0)) {
                        // ošetření tangenty pravého úhlu
                        return fx((0))
                } else {
                        return fx((0))
                }
        } else {
                // vrátit výsledek operace
                return fx_div(y0, x0)
        }
        return
}
 
// fx_sin_cordic_optim - transpiled function from  /root/fx.c:202
func fx_sin_cordic_optim(delta fx) fx {
        // výpočet funkce sin() pro zadaný úhel delta
        var i int32
        var K_fx fx = fx(math.Round(0.6073 * float64(2<<uint64(16-1))))
        // nastavení počátečních podmínek
        var x0 fx = int2fx(1)
        var y0 fx = fx((0))
        var xn fx
        {
                // iterační smyčka
                for i = 0; i < 16; i++ {
                        if delta < fx((0)) {
                                // úhel je záporný => rotace doleva
                                // místo násobení bitový posuv
                                xn = fx_add(x0, y0>>uint64(i))
                                y0 = fx_sub(y0, x0>>uint64(i))
                                delta = fx_add(delta, atans[i])
                        } else {
                                // úhel je kladný => rotace doprava
                                xn = fx_sub(x0, y0>>uint64(i))
                                y0 = fx_add(y0, x0>>uint64(i))
                                delta = fx_sub(delta, atans[i])
                        }
                        x0 = xn
                }
        }
        // opravit "zesílení" výsledku
        return fx_mul(y0, K_fx)
}
 
// fx_cos_cordic_optim - transpiled function from  /root/fx.c:226
func fx_cos_cordic_optim(delta fx) fx {
        // výpočet funkce cos() pro zadaný úhel delta
        var i int32
        var K_fx fx = fx(math.Round(0.6073 * float64(2<<uint64(16-1))))
        // nastavení počátečních podmínek
        var x0 fx = int2fx(1)
        var y0 fx = fx((0))
        var xn fx
        {
                // iterační smyčka
                for i = 0; i < 16; i++ {
                        if delta < fx((0)) {
                                // úhel je záporný => rotace doleva
                                // místo násobení bitový posuv
                                xn = fx_add(x0, y0>>uint64(i))
                                y0 = fx_sub(y0, x0>>uint64(i))
                                delta = fx_add(delta, atans[i])
                        } else {
                                // úhel je kladný => rotace doprava
                                xn = fx_sub(x0, y0>>uint64(i))
                                y0 = fx_add(y0, x0>>uint64(i))
                                delta = fx_sub(delta, atans[i])
                        }
                        x0 = xn
                }
        }
        // opravit "zesílení" výsledku
        return fx_mul(x0, K_fx)
}
 
// fx_sin_cordic_optim_iter - transpiled function from  /root/fx.c:250
func fx_sin_cordic_optim_iter(delta fx, iter int32) fx {
        // výpočet funkce sin() pro zadaný úhel delta
        var i int32
        var K_fx fx = fx(math.Round(0.6073 * float64(2<<uint64(16-1))))
        // nastavení počátečních podmínek
        var x0 fx = int2fx(1)
        var y0 fx = fx((0))
        var xn fx
        {
                // iterační smyčka
                for i = 0; i < iter; i++ {
                        if delta < fx((0)) {
                                // úhel je záporný => rotace doleva
                                // místo násobení bitový posuv
                                xn = fx_add(x0, y0>>uint64(i))
                                y0 = fx_sub(y0, x0>>uint64(i))
                                delta = fx_add(delta, atans[i])
                        } else {
                                // úhel je kladný => rotace doprava
                                xn = fx_sub(x0, y0>>uint64(i))
                                y0 = fx_add(y0, x0>>uint64(i))
                                delta = fx_sub(delta, atans[i])
                        }
                        x0 = xn
                }
        }
        // opravit "zesílení" výsledku
        return fx_mul(y0, K_fx)
}
 
// fx_cos_cordic_optim_iter - transpiled function from  /root/fx.c:274
func fx_cos_cordic_optim_iter(delta fx, iter int32) fx {
        // výpočet funkce cos() pro zadaný úhel delta
        var i int32
        var K_fx fx = fx(math.Round(0.6073 * float64(2<<uint64(16-1))))
        // nastavení počátečních podmínek
        var x0 fx = int2fx(1)
        var y0 fx = fx((0))
        var xn fx
        {
                // iterační smyčka
                for i = 0; i < iter; i++ {
                        if delta < fx((0)) {
                                // úhel je záporný => rotace doleva
                                // místo násobení bitový posuv
                                xn = fx_add(x0, y0>>uint64(i))
                                y0 = fx_sub(y0, x0>>uint64(i))
                                delta = fx_add(delta, atans[i])
                        } else {
                                // úhel je kladný => rotace doprava
                                xn = fx_sub(x0, y0>>uint64(i))
                                y0 = fx_add(y0, x0>>uint64(i))
                                delta = fx_sub(delta, atans[i])
                        }
                        x0 = xn
                }
        }
        // opravit "zesílení" výsledku
        return fx_mul(x0, K_fx)
}
 
// main - transpiled function from  /root/fx.c:297
func main() {
        defer noarch.AtexitRun()
        var i int32
        var cosfx fx
        // úhel, ze kterého se funkce počítá
        var delta float64
        // vypočtené hodnoty
        var value float64
        // absolutní chyby
        var abs_err float64
        // relativní chyby
        var rel_err float64
        // ukazatele na konstantní řetězce pro
        var zvyr1 []byte
        var zvyr2 []byte
        // generování HTML
        fx_create_tables()
        noarch.Puts([]byte("\n<h2>Výpočet funkce cos() optimalizovanou metodou CORDIC</h2>\n\x00"))
        noarch.Puts([]byte("<table>\x00"))
        fmt.Printf("<tr><th>Úhel</th><th>cos FP</th><th>cos FX</th><th>Abs.chyba</th><th>Rel.chyba</th></tr>\n")
        {
                // výpočetní smyčka
                for i = 0; i <= 90; i++ {
                        // převod úhlu na radiány
                        delta = float64(i) / 180 * 3.141592653589793
                        // aplikace algoritmu CORDIC
                        cosfx = fx_cos_cordic_optim(fp2fx(delta))
                        // výpočet funkce cos
                        value = fx2fp(cosfx)
                        // výpočet absolutních chyb
                        abs_err = math.Abs(value - math.Cos(delta))
                        if math.Cos(delta) <= 1e-10 {
                                rel_err = 0
                        } else {
                                rel_err = 100 * abs_err / math.Cos(delta)
                        }
                        if rel_err <= 1 {
                                zvyr1 = []byte("<strong>\x00")
                                zvyr2 = []byte("</strong>\x00")
                        } else {
                                zvyr1 = []byte("\x00")
                                zvyr2 = []byte("\x00")
                        }
                        noarch.Printf([]byte("<tr><td>%02d</td><td>%5.3f</td><td>%5.3f%%</td><td>%5.3f</td><td>%s%5.3f%%%s</td></tr>\n\x00"), i, value, math.Cos(delta), abs_err, zvyr1, rel_err, zvyr2)
                }
        }
        noarch.Puts([]byte("</table>\x00"))
        return
}
 
// finito
Poznámka: zdrojový kód upraveného programu naleznete na adrese https://github.com/tisnik/go-root/blob/master/article97/fx_co­rrected.go.

15. Porovnání výsledků výpočtů

Výsledky vypočtené originálním programem napsaným v céčku jsou naprosto shodné s výsledky, které lze získat transpilovaným programem reprezentovaným v jazyce Go. Zde je uvedena pouze krátká ukázka vygenerované tabulky s výsledky:

Úhel cos FP cos FX Abs.chyba Rel.chyba
00 0.996 1.000% 0.004 0.429%
01 0.996 1.000% 0.004 0.414%
02 0.996 0.999% 0.004 0.368%
03 0.993 0.999% 0.005 0.529%
04 0.993 0.998% 0.004 0.423%
05 0.991 0.996% 0.005 0.523%
06 0.991 0.995% 0.004 0.356%
07 0.989 0.993% 0.004 0.396%
08 0.986 0.990% 0.004 0.406%
09 0.984 0.988% 0.004 0.385%
10 0.982 0.985% 0.003 0.334%
76 0.239 0.242% 0.003 1.259%
77 0.222 0.225% 0.003 1.169%
78 0.206 0.208% 0.002 1.033%
79 0.189 0.191% 0.002 0.839%
80 0.173 0.174% 0.001 0.573%
81 0.154 0.156% 0.003 1.727%
82 0.137 0.139% 0.002 1.435%
83 0.121 0.122% 0.001 1.025%
84 0.104 0.105% 0.000 0.443%
85 0.085 0.087% 0.002 2.308%
86 0.069 0.070% 0.001 1.675%
87 0.052 0.052% 0.000 0.580%
88 0.033 0.035% 0.002 5.123%
89 0.017 0.017% 0.001 5.138%
90 –0.002 0.000% 0.002 0.000%

16. Program psaný v C, který vytváří a manipuluje se stromovou datovou strukturou

Poslední příklad, který si dnes ukážeme, je opět psaný v jazyku C. Najdeme v něm triviální implementaci konstrukce binárního stromu pro uložení řetězců společně s funkcí pro průchod (traverzaci) tímto stromem. V tomto příkladu se tedy zaměřujeme na operace s ukazateli, využití struktur obsahujících ukazatele, dynamickou alokaci paměti atd. (tedy operace, které se v Go většinou provádí odlišně, než je tomu v jazyku C):

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
 
typedef struct Node
{
    struct Node *left;
    struct Node *right;
    char *value;
} Node;
 
void insert_new_node(Node **root, char *value)
{
    int cmp;
 
    if (*root == NULL)
    {
        *root = (Node *)malloc(sizeof(Node));
        (*root)->value = (char*)calloc(strlen(value), sizeof(char));
        strcpy((*root)->value, value);
        (*root)->left = NULL;
        (*root)->right = NULL;
        return;
    }
    cmp = strcmp(value, (*root)->value);
    if (cmp < 0)
    {
        insert_new_node(&(*root)->left, value);
    }
    else
    {
        insert_new_node(&(*root)->right, value);
    }
}
 
void traverse_tree(Node *root, void (*callback_function)(char *))
{
    if (root == NULL)
    {
        return;
    }
    traverse_tree(root->left, callback_function);
    callback_function(root->value);
    traverse_tree(root->right, callback_function);
}
 
void callback_function(char *value)
{
    printf("%s\n", value);
}
 
int main(void)
{
    static Node *root = NULL;
 
    insert_new_node(&root, "xxx");
    insert_new_node(&root, "aaa");
    insert_new_node(&root, "bbb");
    insert_new_node(&root, "ccc");
    insert_new_node(&root, "yyy");
    insert_new_node(&root, "yyy");
 
    traverse_tree(root, callback_function);
 
    return 0;
}
Poznámka: zdrojový kód tohoto prográmku naleznete na adrese https://github.com/tisnik/go-root/blob/master/article97/tree.c.

17. Výsledek transpilace programu do jazyka Go

Program z předchozí kapitoly se transpřeloží do tohoto zdrojového kódu reprezentovaného v jazyce Go:

//
//      Package - transpiled by c4go
//
//      If you have found any issues, please raise an issue at:
//      https://github.com/Konstantin8105/c4go/
//
 
package main
 
import "unsafe"
import "github.com/Konstantin8105/c4go/noarch"
 
// Node - transpiled function from  /root/tree.c:5
type Node struct {
        left  []Node
        right []Node
        value []byte
}
 
// insert_new_node - transpiled function from  /root/tree.c:12
func insert_new_node(root [][]Node, value []byte) {
        var cmp int32
        if len(root[0]) == 0 {
                root[0] = make([]Node, 1)
                (root[0])[0].value = make([]byte, noarch.Strlen(value))
                noarch.Strcpy((root[0])[0].value, value)
                (root[0])[0].left = nil
                (root[0])[0].right = nil
                return
        }
        cmp = noarch.Strcmp(value, (root[0])[0].value)
        if cmp < 0 {
                insert_new_node((*[1000000][]Node)(unsafe.Pointer(&(root[0])[0].left))[:], value)
        } else {
                insert_new_node((*[1000000][]Node)(unsafe.Pointer(&(root[0])[0].right))[:], value)
        }
}
 
// traverse_tree - transpiled function from  /root/tree.c:36
func traverse_tree(root []Node, callback_function func([]byte)) {
        if len(root) == 0 {
                return
        }
        traverse_tree(root[0].left, callback_function)
        callback_function(root[0].value)
        traverse_tree(root[0].right, callback_function)
}
 
// callback_function - transpiled function from  /root/tree.c:47
func callback_function(value []byte) {
        noarch.Printf([]byte("%s\n\x00"), value)
}
 
// main - transpiled function from  /root/tree.c:52
func main() {
        defer noarch.AtexitRun()
        var root []Node
        insert_new_node((*[1000000][]Node)(unsafe.Pointer(&root))[:], []byte("xxx\x00"))
        insert_new_node((*[1000000][]Node)(unsafe.Pointer(&root))[:], []byte("aaa\x00"))
        insert_new_node((*[1000000][]Node)(unsafe.Pointer(&root))[:], []byte("bbb\x00"))
        insert_new_node((*[1000000][]Node)(unsafe.Pointer(&root))[:], []byte("ccc\x00"))
        insert_new_node((*[1000000][]Node)(unsafe.Pointer(&root))[:], []byte("yyy\x00"))
        insert_new_node((*[1000000][]Node)(unsafe.Pointer(&root))[:], []byte("yyy\x00"))
        traverse_tree(root, callback_function)
        return
}
Poznámka: zdrojový kód transpilovaného programu naleznete na adrese https://github.com/tisnik/go-root/blob/master/article97/tree.go.

Tento program ovšem po svém spuštění zhavaruje:

panic: runtime error: index out of range [3] with length 3
 
goroutine 1 [running]:
github.com/Konstantin8105/c4go/noarch.Strcpy(...)
        /home/ptisnovs/go/pkg/mod/github.com/!konstantin8105/c4go@v0.0.0-20211115111653-1c67b1543446/noarch/string.go:30
main.insert_new_node({0xc0000aff50, 0xc000048738?, 0x4589fb?}, {0xc0000aff44, 0x4, 0xc0000021a0?})
        /home/ptisnovs/src/go-root/article_97/tree.go:26 +0x28a
main.main()
        /home/ptisnovs/src/go-root/article_97/tree.go:58 +0x70
exit status 2

18. Oprava předchozího programu

Oprava spočívá v tom, že se upraví velikost bloku pro kopírovaný řetězec – viz též zvýrazněný kód. Po této úpravě bude manipulace se stromem probíhat korektně:

//
//      Package - transpiled by c4go
//
//      If you have found any issues, please raise an issue at:
//      https://github.com/Konstantin8105/c4go/
//
 
package main
 
import "unsafe"
import "github.com/Konstantin8105/c4go/noarch"
 
// Node - transpiled function from  /root/tree.c:5
type Node struct {
        left  []Node
        right []Node
        value []byte
}
 
// insert_new_node - transpiled function from  /root/tree.c:12
func insert_new_node(root [][]Node, value []byte) {
        var cmp int32
        if len(root[0]) == 0 {
                root[0] = make([]Node, 1)
                (root[0])[0].value = make([]byte, 1+noarch.Strlen(value))
                noarch.Strcpy((root[0])[0].value, value)
                (root[0])[0].left = nil
                (root[0])[0].right = nil
                return
        }
        cmp = noarch.Strcmp(value, (root[0])[0].value)
        if cmp < 0 {
                insert_new_node((*[1000000][]Node)(unsafe.Pointer(&(root[0])[0].left))[:], value)
        } else {
                insert_new_node((*[1000000][]Node)(unsafe.Pointer(&(root[0])[0].right))[:], value)
        }
}
 
// traverse_tree - transpiled function from  /root/tree.c:36
func traverse_tree(root []Node, callback_function func([]byte)) {
        if len(root) == 0 {
                return
        }
        traverse_tree(root[0].left, callback_function)
        callback_function(root[0].value)
        traverse_tree(root[0].right, callback_function)
}
 
// callback_function - transpiled function from  /root/tree.c:47
func callback_function(value []byte) {
        noarch.Printf([]byte("%s\n\x00"), value)
}
 
// main - transpiled function from  /root/tree.c:52
func main() {
        defer noarch.AtexitRun()
        var root []Node
        insert_new_node((*[1000000][]Node)(unsafe.Pointer(&root))[:], []byte("xxx\x00"))
        insert_new_node((*[1000000][]Node)(unsafe.Pointer(&root))[:], []byte("aaa\x00"))
        insert_new_node((*[1000000][]Node)(unsafe.Pointer(&root))[:], []byte("bbb\x00"))
        insert_new_node((*[1000000][]Node)(unsafe.Pointer(&root))[:], []byte("ccc\x00"))
        insert_new_node((*[1000000][]Node)(unsafe.Pointer(&root))[:], []byte("yyy\x00"))
        insert_new_node((*[1000000][]Node)(unsafe.Pointer(&root))[:], []byte("yyy\x00"))
        traverse_tree(root, callback_function)
        return
}
Poznámka: o dealokaci jednotlivých uzlů se samozřejmě v jazyce Go nemusíme starat.

19. Repositář s demonstračními příklady

Zdrojové kódy všech dnes použitých demonstračních příkladů byly uloženy do nového Git repositáře, který je dostupný na adrese https://github.com/tisnik/go-root (stále na GitHubu :-). V případě, že nebudete chtít klonovat celý repositář (ten je ovšem – alespoň prozatím – velmi malý, dnes má přibližně stovku kilobajtů), můžete namísto toho použít odkazy na jednotlivé demonstrační příklady, které naleznete v následující tabulce:

# Příklad/soubor Stručný popis Cesta
1 hello.c klasický program typu „Hello world“ zapsaný v jazyku C https://github.com/tisnik/go-root/blob/master/article97/hello.c
2 hello.go soubor hello.c transpilovaný do jazyka Go https://github.com/tisnik/go-root/blob/master/article97/hello.go
3 strings1.c základní manipulace s řetězci v C https://github.com/tisnik/go-root/blob/master/article97/strin­gs1.c
4 strings1.go soubor strings1.c transpilovaný do jazyka Go https://github.com/tisnik/go-root/blob/master/article97/strin­gs1.go
5 strings2.c modifikace řetězců v C https://github.com/tisnik/go-root/blob/master/article97/strin­gs2.c
6 strings2.go soubor strings2.c transpilovaný do jazyka Go https://github.com/tisnik/go-root/blob/master/article97/strin­gs2.go
7 fp.c algoritmus CORDIC zapsaný v C a založený na FP aritmetice https://github.com/tisnik/go-root/blob/master/article97/fp.c
8 fp_transpiled.go soubor fp.c transpilovaný do jazyka Go https://github.com/tisnik/go-root/blob/master/article97/fp_tran­spiled.go
9 fp_corrected.go úprava předchozího zdrojového kódu do korektní podoby https://github.com/tisnik/go-root/blob/master/article97/fp_co­rrected.go
10 fx.c algoritmus CORDIC zapsaný v C a založený na fixed point aritmetice https://github.com/tisnik/go-root/blob/master/article97/fx.c
12 fx_transpiled.go soubor fx.c transpilovaný do jazyka Go https://github.com/tisnik/go-root/blob/master/article97/fx_tran­spiled.go
11 fx_corrected.go úprava předchozího zdrojového kódu do korektní podoby https://github.com/tisnik/go-root/blob/master/article97/fx_co­rrected.go
13 tree.c vytvoření a manipulace s binárním stromem v jazyku C https://github.com/tisnik/go-root/blob/master/article97/tree.c
14 tree.go soubor tree.c transpilovaný do jazyka Go https://github.com/tisnik/go-root/blob/master/article97/tree.go
15 tree_corrected.go úprava předchozího zdrojového kódu do korektní podoby https://github.com/tisnik/go-root/blob/master/article97/tre­e_corrected.go

20. Odkazy na Internetu

  1. c4go na GitHubu
    https://github.com/Konstan­tin8105/c4go
  2. Source-to-source compiler (Wikipedia)
    https://en.wikipedia.org/wiki/Source-to-source_compiler
  3. Clang: a C language family frontend for LLVM
    https://clang.llvm.org/
  4. The LLVM Compiler Infrastructure
    https://llvm.org/
  5. Abstract syntax tree
    https://en.wikipedia.org/wi­ki/Abstract_syntax_tree
  6. List of transpilers, sorted by target language
    https://github.com/jarble/list-of-transpilers
  7. Awesome WebAssembly Languages Awesome
    https://github.com/appcypher/awesome-wasm-langs
  8. Compilers targeting C
    https://github.com/dbohdan/compilers-targeting-c
  9. History of compiler construction
    https://en.wikipedia.org/wi­ki/History_of_compiler_con­struction
  10. Golang AST Package
    https://golangdocs.com/golang-ast-package
  11. Rune literals
    https://go.dev/ref/spec#Rune_literals
  12. Výpočet goniometrických funkcí algoritmem CORDIC
    https://www.root.cz/clanky/vypocet-goniometrickych-funkci-algoritmem-cordic/
  13. Metoda CORDIC a výpočet funkcí tan, atan a length
    https://www.root.cz/clanky/metoda-cordic-a-vypocet-funkci-tan-atan-a-length/
  14. Algoritmus CORDIC v FX formátu a goniometrické funkce
    https://www.root.cz/clanky/algoritmus-cordic-v-fx-formatu-a-goniometricke-funkce/
  15. Algoritmus CORDIC s hodnotami uloženými ve formátu FX
    https://www.root.cz/clanky/algoritmus-cordic-s-hodnotami-ulozenymi-ve-formatu-fx/
  16. unsafe.Pointer
    https://pkg.go.dev/unsafe#Pointer

Autor článku

Vystudoval VUT FIT a v současné době pracuje na projektech vytvářených v jazycích Python a Go.