Простое любопытство и некоторая необходимость заставили меня проверить работу операций mod и div в различных языках программирования. И должен сказать, что данные эксперименты привели совершенно к неожиданным результатам.

Итак, все началось с моей статьи "Задание 17", в которой я обосновывал результат операций mod и div в языке Python. Напомню основные положения.

Теорема: для любых целых чисел n и q существуют единственным образом определенные целые числа m и r, удовлетворяющие условиям:

\[ \left \{ {n=m \cdot q+r\\0 \leq |r| <|q|\\Sign(q)=Sign(r)}  \right.\] , где Sign(x) — функция определения знака числа x.

Таким образом, будем называть число r остатком от деления n на q, а число m — неполным частным (целой частью) от деления n на q.

Сознаюсь, я добавил некоторые ограничения в данную теорему, но справедливости своей она не потеряла и так же, доказуема. Далее, я рассмотрел, как данная операция работает в языке Python. Думаю, пришло время продемонстрировать код, чтобы мои утверждения могли быть проверены в различных условиях.

Итак, код на языке Python (совсем не изящный, но задача совсем не в этом):

print('n\tq\tn = mq+r\t\tm\tr')

n=147
q=10

print(n,'\t',q,'\t',n ,'=',n//q,'*',q,'+',n%q,'\t',n//q,'\t',n%q)

n=-147
q=10

print(n,'\t',q,'\t',n ,'=',n//q,'*',q,'+',n%q,'\t',n//q,'\t',n%q)

n=147
q=-10

print(n,'\t',q,'\t',n ,'=',n//q,'*',q,'+',n%q,'\t',n//q,'\t',n%q)

n=-147
q=-10

print(n,'\t',q,'\t',n ,'=',n//q,'*',q,'+',n%q,'\t',n//q,'\t',n%q)

Получился следующий результат:

 

n

q

\[ n=m \cdot q + r\]

m

r

147

10

\[ 147=14 \cdot 10+7\]

14

7

-147

10

\[ -147=-15 \cdot 10 +3\]

-15

3

147

-10

\[ 147 = -15 \cdot (-10)-3\]

-15

-3

-147

-10

\[-147 = 14 \cdot(-10) - 7\]

14

-7

И вот, я решил проверить подобный код на языке C++.

Собственно, код:

#include <iostream>

using namespace std;

int main()
{
    int n=147;
    int q=10;

    cout << "n\tq\tm*q+r\t\tm\tr"   << endl;
    cout << n<<"\t"<<q<<"\t"<<n/q<<"*"<<q<<"+"<<n%q<<"\t\t"<<n/q<<"\t"<<n%q<<endl;
    n=-147;
    cout << n<<"\t"<<q<<"\t"<<n/q<<"*"<<q<<"+"<<n%q<<"\t"<<n/q<<"\t"<<n%q<<endl;
    n=147;
    q=-10;
    cout << n<<"\t"<<q<<"\t"<<n/q<<"*"<<q<<"+"<<n%q<<"\t"<<n/q<<"\t"<<n%q<<endl;
    n=-147;
    cout << n<<"\t"<<q<<"\t"<<n/q<<"*"<<q<<"+"<<n%q<<"\t"<<n/q<<"\t"<<n%q<<endl;

    return 0;
}

Данный код был скомпилирован с помощью компилятора LLVM clang-7 под операционной системой Debian 10.

Результат был неожиданным:

n

q

\[ n=m \cdot q + r\]

m

r

147

10

\[ 147=14 \cdot 10+7\]

14

7

-147

10

\[ -147=-14 \cdot 10 -7\]

-14

-7

147

-10

\[ 147 = -14 \cdot(-10)+7\]

-14

7

-147

-10

\[-147 = 14 \cdot(-10) - 7\]

14

-7

 

Итак, что мы видим? Равенство знаков q и r не соблюдается, но знаки m и r подбираются таким образом, чтобы с одной стороны, выражение \[n=m\cdot q+r\] сохраняло свою справедливость, с другой стороны сохранялось следующее равенство: \[ |r|=|n|\mod |q| \]то есть, последняя цифра записи числа равнялась абсолютному значению остатка от деления на основание системы счисления.

Компиляция с помощью g++ 8.3.0 дала точно такой же результат.

Далее, рассмотрим код на Pascal:

var
	n,q	: integer;
	
begin
	writeln('n	q	n=m*q+r		m	r');
	n:=147;
	q:=10;
	writeln(n,'	',q,'	',n,'=',n div q,'*',q,'+',n mod q,'	',n div q,'	', n mod q);
	n:=-147;
	q:=10;
	writeln(n,'	',q,'	',n,'=',n div q,'*',q,'+',n mod q,'	',n div q,'	', n mod q);
	n:=147;
	q:=-10;
	writeln(n,'	',q,'	',n,'=',n div q,'*',q,'+',n mod q,'	',n div q,'	', n mod q);
	n:=-147;
	q:=-10;
	writeln(n,'	',q,'	',n,'=',n div q,'*',q,'+',n mod q,'	',n div q,'	', n mod q);
	
end.

Компилятор fpc 3.0.4

Результат аналогичен результату на C++.

Я пока не стал рассматривать такие языки, как C, C#, Java и прочие, так как в школьном образовании они, скорее, экзоты, нежели обыденность. Но, проверка данного аспекта была бы интересна. Особенно, на разных операционных системах, компиляторах и так далее. В ОС Linux, думаю, результаты будут сопоставимы, так как для всех компилируемых языков все сводится к вызовам библиотеки libc. А вот под ОС Windows результаты могут быть неожиданные, так как разные системы могут использовать свои собственные библиотеки.

В рамках данного исследования, результаты, полученные на языке Python уже кажутся мне более неожиданными и менее логичными, нежели на других языках. Но в любом случае, мы видим, что базовая теорема теории чисел сохраняет свою справедливость, а языки программирования следуют этой теореме, хотя и несколько различными способами.

В целом, данный материал предназначен для учащихся высокого уровня мотивации, которым важен каждый балл ЕГЭ и участвующим в олимпиадах, где малейшая деталь может сыграть роковую роль в итоговом результате.

Учите математику, исследуйте системы программирования, подвергайте все сомнению и тщательной проверке - и вы станете классным специалистом...