keskiviikko 27. heinäkuuta 2022

LibreOfficen MOD-funktio ei toimi!

Käytän LibreOfficen taulukkolaskentaa mm. algoritmien suunnitteluun. Taulukkolaskenta on hyvä työkalu tähän tarkoitukseen, koska algoritmia voi testata erilaisilla syötteillä jo ennen kuin algoritmia tarvitsee toteuttaa millään oikealla ohjelmointikielellä. Erästä algoritmia toteuttaessani huomasin kuitenkin, että LibreOfficen MOD-funktio toimii eri tavalla kuin ohjelmointikielissä yleensä.

MOD-funktiolla lasketaan kahden kokonaisluvun jakojäännös: jos esimerkiksi 9 jaetaan 5:llä, niin 5 mahtuu 9:ään yhden kerran ja jäljelle jää 4. Jos jakajan ja jaettavan etumerkit kuitenkin poikkeavat toisistaan, niin LibreOffice MOD-funktio antaa yllättävän tuloksen. Esimerkiksi -9 jaettuna 12 antaa Libreoffice 7.3.4.2:ssa jakojäännökseksi 3:
Vastaavasti C-kielessä (GCC 12.1.0) sama laskukaava antaa tulokseksi -9:
#include <stdio.h>

int main(void) {
        printf("vastaus=%d\n", -9 % 12);
        return 0;
}
> gcc x.c > ./a.out vastaus=-9

Kyseessä ei ole bugi, vaan jakojäännös voidaan laskea usealla eri algoritmilla ja ohjelmointikielet poikkeavat toisistaan tässä suhteessa: When exactly one of a or n is negative, the naïve definition breaks down, and programming languages differ in how these values are defined. LibreOffice käyttää jakojäännöksen laskemiseen Knuthin algoritmia kun ohjelmointikielet yleensä käyttävät kokonaislukujen jakojäännöksen laskemiseen ns. "truncated division" algoritmia.

LibreOfficessa jakojäännös "truncated division" algoritmilla saadaan kaavalla MOD(ABS(A); ABS(B)) * SIGN(A), missä A on jaettava ja B on jakaja:
Ero on hyvä pitää mielessä, jos käyttää LibreOfficea algoritmien kehittämiseen!