bajt + bajt = int… dlaczego?

365

Patrząc na ten kod C #:

byte x = 1;
byte y = 2;
byte z = x + y; // ERROR: Cannot implicitly convert type 'int' to 'byte'

Wynik dowolnej matematyki wykonanej na typach byte(lub short) jest domyślnie rzutowany z powrotem na liczbę całkowitą. Rozwiązaniem jest jawne przeniesienie wyniku z powrotem do bajtu:

byte z = (byte)(x + y); // this works

Zastanawiam się, dlaczego? Czy to jest architektoniczne? Filozoficzny?

Mamy:

  • int+ int=int
  • long+ long=long
  • float+ float=float
  • double+ double=double

Dlaczego więc nie:

  • byte+ byte=byte
  • short+ short= short?

Trochę tła: wykonuję długą listę obliczeń dla „małych liczb” (tj. <8) i przechowuję wyniki pośrednie w dużej tablicy. Korzystanie z tablicy bajtów (zamiast tablicy int) jest szybsze (z powodu trafień w pamięci podręcznej). Ale rozległe rzutowania bajtów rozłożone w kodzie sprawiają, że jest on o wiele bardziej nieczytelny.

Robert Cartaino
źródło
10
Przydałaby się tu nie znajomość standardu przez Erica - to jego znajomość konstrukcji języka; co nie dlaczego Ale tak, odpowiedź Erica byłaby dość ostateczna :)
Jon Skeet
143
Różne rozważania poniżej są rozsądnym przybliżeniem rozważań projektowych. Mówiąc bardziej ogólnie: nie uważam bajtów za „liczby”; Myślę o nich jak o wzorach bitów, które można interpretować jako liczby, znaki, kolory lub cokolwiek innego. Jeśli zamierzasz robić na nich matematykę i traktować je jako liczby, wówczas sensowne jest przeniesienie wyniku do typu danych, który jest częściej interpretowany jako liczba.
Eric Lippert
28
@Eric: To ma sens w przypadku bajtu, ale prawdopodobnie nie ma tak dużego sensu w przypadku krótkiego / ushort.
Jon Skeet
23
@Eric: byte1 | byte2wcale nie traktuje ich jak liczb. To traktuje je dokładnie jako wzory bitów. Rozumiem twój punkt widzenia, ale tak się składa, że ​​za każdym razem, gdy robiłem jakąkolwiek arytmetykę na bajtach w C #, faktycznie traktowałem je jako bity, a nie liczby, a takie zachowanie zawsze przeszkadza.
Roman Starkov

Odpowiedzi:

228

Trzeci wiersz fragmentu kodu:

byte z = x + y;

właściwie znaczy

byte z = (int) x + (int) y;

Tak więc nie ma operacji + na bajtach, bajty są najpierw rzutowane na liczby całkowite, a wynikiem dodania dwóch liczb całkowitych jest (32-bitowa) liczba całkowita.

azheglov
źródło
Próbowałem kodu poniżej, ale nadal nie działa. bajt z = (bajt) x + (bajt) y;
Anonimowy
10
to dlatego, że nie ma operacji + dla bajtów (patrz wyżej). Spróbuj bajt z = (bajt) ((int) x + (int) y)
azheglov
35
To musi być najbardziej poprawna, zwięzła odpowiedź. Między bajtami nie ma żadnego argumentu, więc zamiast wyjaśniać, dlaczego „dodawanie dwóch bajtów” działa, czy nie ( nigdy się nie zdarzyło ), to wyraźnie pokazuje, dlaczego wynikiem jest liczba całkowita , ponieważ jedyną rzeczą, która się wydarzyła, jest dodanie 2 liczb wewnętrznych .
RichardTheKiwi
2
Miałem zawroty głowy, czytając wszystkie pozostałe odpowiedzi (bez obrazy dla pana Jona Skeeta). To jest najprostsza odpowiedź, która poprawnie opisuje to, co dzieje się pod maską. Dzięki!
rayryeng
Oto odpowiedź, którą napisałem gdzie indziej, która zawiera program służący do identyfikacji, kiedy ta automatyczna promocja oparta na kompilatorze intma miejsce: stackoverflow.com/a/43578929/4561887
Gabriel Staples
172

Jeśli chodzi o „dlaczego tak się dzieje”, to dlatego, że nie ma żadnych operatorów zdefiniowanych przez C # dla arytmetyki z bajtem, sbyte, short lub ushort, tak jak mówili inni. Ta odpowiedź dotyczy powodów, dla których nie zdefiniowano tych operatorów.

Wierzę, że to w zasadzie ze względu na wydajność. Procesory mają natywne operacje do wykonywania arytmetyki z 32 bitami bardzo szybko. Automatyczne przekształcenie z wyniku na bajt może być wykonane automatycznie , ale skutkowałoby to karami wydajnościowymi w przypadku, gdy tak naprawdę nie chcesz tego zachowania.

Myślę, że jest to wspomniane w jednym z adnotowanych standardów C #. Szukam ...

EDYCJA: Irytujące, przejrzałem teraz specyfikację ECMA C # 2 z adnotacją, specyfikację MS C # 3 z adnotacją i specyfikację CLI adnotacji, i żadne z nich nie wspomina o tym, o ile widzę. Jestem pewien , że widziałem powód podany powyżej, ale jestem pod wrażeniem, jeśli wiem, gdzie. Przepraszamy, fani referencji :(

Jon Skeet
źródło
14
Przykro mi to mówić, ale nie jest to najlepsza odpowiedź.
VVS
42
Czy zanegowałeś każdą odpowiedź, która nie jest najlepsza? ;)
Jon Skeet
55
(Żeby wyjaśnić, tak naprawdę nie mam ochoty na ciebie. Wygląda na to, że każdy ma swoje własne kryteria głosowania w dół, i to jest w porządku. Głosuję tylko za odpowiedzią, jeśli uważam, że jest to czynnie szkodliwe, a nie po prostu idealne. )
Jon Skeet
21
Używam głosowania jako narzędzia, aby uzyskać „najlepszą” odpowiedź na górę. W rzeczywistości stwierdziłem, że w swojej odpowiedzi niewiele powiedziałeś, co było głównym powodem mojej opinii. Innym powodem może być moje subiektywne odczucie, że twój przedstawiciel daje ci dużą premię, jeśli chodzi o głosowanie i lądujesz na „lepszych” odpowiedziach.
VVS
23
IMO najlepszym sposobem na uzyskanie „najlepszej” odpowiedzi na górę jest głosowanie za nią. Szczerze mówiąc, myślę, że najbardziej pouczającą odpowiedzią jest tutaj komentarz Erica w pytaniu ... ale poza tym, jeśli chodzi o perspektywę projektowania (w przeciwieństwie do perspektywy „tego, co robi kompilator”), nie sądzę, że jest wiele odpowiedź poza „wydajnością”. W szczególności tak naprawdę nie kupuję argumentu „zapobiega przepełnieniu” (17 głosów), ponieważ sugerowałoby to int + int = long.
Jon Skeet
68

Myślałem, że już gdzieś to widziałem. Z tego artykułu The Old New Thing :

Załóżmy, że żyliśmy w świecie fantasy, w którym operacje na „bajcie” skutkowały „bajtem”.

byte b = 32;
byte c = 240;
int i = b + c; // what is i?

W tym świecie fantasy wartość i wyniosłaby 16! Dlaczego? Ponieważ oba operandy operatora + są bajtami, więc suma „b + c” jest obliczana jako bajt, co powoduje 16 z powodu przepełnienia liczb całkowitych. (I, jak zauważyłem wcześniej, przepełnienie liczb całkowitych jest nowym wektorem ataku bezpieczeństwa.)

EDYCJA : Raymond broni zasadniczo podejścia C i C ++ pierwotnie przyjętego. W komentarzach broni faktu, że C # przyjmuje to samo podejście, ze względu na kompatybilność wsteczną języka.

Michael Petrotta
źródło
42
W przypadku liczb całkowitych, jeśli je dodamy i przepełnia się, nie jest automatycznie przesyłany jako inny typ danych, ale dlaczego to robić z bajtem?
Ryan
2
Z ints robi się przepełniony. Spróbuj dodać int.MaxValue + 1, otrzymujesz -2147483648 zamiast 2147483648.
David Basarab
8
@ Longhorn213: Tak, tak mówi Ryan: int matematyka może się przepełnić, ale matematyka int nie zwraca długich.
Michael Petrotta
28
Dokładnie. Jeśli ma to być środek bezpieczeństwa, to bardzo źle wdrożony;)
Jon Skeet
5
@Ryan: „leniwy” to dość poważny zarzut w stosunku do projektantów języka C #, za coś tak podstawowego jak prymitywna matematyka. Jeśli chcesz ich o coś oskarżyć, uczyń to „nadmierną kompatybilnością wsteczną z C / C ++”.
Michael Petrotta
58

DO#

ECMA-334 stwierdza, że ​​dodawanie jest zdefiniowane jako legalne tylko dla int + int, uint + uint, long + long i ultrong + ulong (ECMA-334 14.7.4). Jako takie, są to operacje kandydujące do rozważenia w odniesieniu do 14.4.2. Ponieważ istnieją niejawne rzutowania z bajtu na int, uint, long i ultrong, wszystkie elementy funkcji dodawania są odpowiednimi elementami funkcji zgodnie z 14.4.2.1. Musimy znaleźć najlepszą domyślną obsadę według reguł w 14.4.2.3:

Rzutowanie (C1) na int (T1) jest lepsze niż rzutowanie (C2) na uint (T2) lub ulong (T2), ponieważ:

  • Jeśli T1 jest int, a T2 jest uint lub ulong, C1 jest lepszą konwersją.

Rzutowanie (C1) na int (T1) jest lepsze niż rzutowanie (C2) na długi (T2), ponieważ istnieje ukryty rzut z int na długi:

  • Jeśli istnieje niejawna konwersja z T1 do T2 i nie istnieje niejawna konwersja z T2 do T1, C1 jest lepszą konwersją.

Dlatego używana jest funkcja int + int, która zwraca wartość int.

Co jest bardzo długą drogą do stwierdzenia, że ​​jest głęboko schowany w specyfikacji C #.

CLI

Interfejs CLI działa tylko na 6 typach (int32, native int, int64, F, O i &). (ECMA-335 partycja 3 sekcja 1.5)

Bajt (int8) nie jest jednym z tych typów i jest automatycznie konwertowany na int32 przed dodaniem. (ECMA-335 partycja 3 sekcja 1.6)

Alun Harford
źródło
To, że ECMA określa tylko te konkretne operacje, nie uniemożliwiłoby językowi wdrożenia innych przepisów. VB.NET zezwoli byte3 = byte1 And byte2bez użycia rzutowania, ale bezskutecznie rzuci wyjątek środowiska wykonawczego, jeśli zwróci int1 = byte1 + byte2wartość powyżej 255. Nie wiem, czy którykolwiek język zezwoli byte3 = byte1+byte2i wyrzuci wyjątek, gdy przekroczy 255, ale nie wyrzuci wyjątku, jeśli int1 = byte1+byte2zwróci wartość z zakresu 256–510.
supercat
26

Odpowiedzi wskazujące na nieefektywność dodawania bajtów i obcięcia wyniku z powrotem do bajtu są niepoprawne. Procesory x86 mają instrukcje specjalnie zaprojektowane do działania na liczbach całkowitych w ilościach 8-bitowych.

W rzeczywistości dla procesorów x86 / 64 wykonywanie operacji 32-bitowych lub 16-bitowych jest mniej wydajne niż operacji 64-bitowych lub 8-bitowych ze względu na bajt prefiksu argumentu, który należy zdekodować. Na maszynach 32-bitowych wykonywanie operacji 16-bitowych wiąże się z taką samą karą, ale nadal istnieją dedykowane kody dla operacji 8-bitowych.

Wiele architektur RISC ma podobne rodzime instrukcje wydajne słowo / bajt. Te, które na ogół nie mają wartości przechowywania-i-konwersji-do-podpisanej-o-pewnej długości.

Innymi słowy, ta decyzja musiała być oparta na percepcji typu bajtu, a nie z powodu leżącej u podstaw nieefektywności sprzętu.

Krzysztof
źródło
+1; gdyby tylko ta percepcja nie była błędna za każdym razem, gdy kiedykolwiek się zmieniłem, LUB OR dwa bajty w C # ...
Roman Starkov
Obcinanie wyniku nie powinno wiązać się z żadnymi kosztami wydajności. W asemblerze x86 jest to tylko różnica między kopiowaniem jednego bajtu z rejestru lub czterech bajtów z rejestru.
Jonathan Allen,
1
@JonathanAllen Dokładnie. Jedyną różnicą jest, o ironio, przy przeprowadzaniu konwersji rozszerzającej . Obecny projekt karę wydajności do wykonania instrukcji rozszerzający (albo podpisali rozszerzyć lub niepodpisanych przedłużyć.)
reirab
percepcja typu bajtu ” - może to wyjaśniać to zachowanie dla byte(i char), ale nie dla shortktórego semantycznie jest wyraźnie liczbą.
smls,
13

Pamiętam, jak raz przeczytałem coś od Jona Skeeta (nie mogę tego teraz znaleźć, będę dalej szukać) o tym, jak bajt nie przeciąża operatora +. W rzeczywistości, podczas dodawania dwóch bajtów jak w twojej próbce, każdy bajt jest w rzeczywistości domyślnie konwertowany na liczbę całkowitą. Wynikiem tego jest oczywiście int. Teraz, DLACZEGO to zostało zaprojektowane w ten sposób, poczekam, aż sam Jon Skeet opublikuje :)

EDYCJA: Znaleziono! Świetne informacje na ten temat tutaj .

BFree
źródło
9

Wynika to z przelania i przenoszenia.

Jeśli dodasz dwie liczby 8-bitowe, mogą one przelać się na 9-ty bit.

Przykład:

  1111 1111
+ 0000 0001
-----------
1 0000 0000

Nie wiem na pewno, ale zakładam, że ints, longsidoubles mają więcej miejsca, ponieważ są dość duże. Są to także wielokrotności 4, które są bardziej wydajne w obsłudze komputerów, ponieważ szerokość wewnętrznej szyny danych wynosi 4 bajty lub 32 bity (64 bity stają się coraz bardziej powszechne). Bajt i skrót są nieco bardziej nieefektywne, ale mogą zaoszczędzić miejsce.

samoz
źródło
23
Ale większe typy danych nie zachowują się tak samo.
Inisheer
12
Problemy związane z przepełnieniem są na bok. Jeśli weźmiesz swoją logikę i zastosujesz ją do języka, wówczas wszystkie typy danych zwrócą większy typ danych po dodaniu arytmetyki, co z całą pewnością NIE jest prawdą. int + int = int, long + long = long. Myślę, że pytanie dotyczy niespójności.
Joseph
To była moja pierwsza myśl, ale dlaczego nie int + int = long? Więc nie kupuję argumentu o „możliwym przepełnieniu” ... jeszcze <grin>.
Robert Cartaino
11
Aha, a jeśli chodzi o argument „możliwe przepełnienie”, dlaczego nie bajt + bajt = krótki?
Robert Cartaino
A) Dlaczego to działa tak, jak działa, biorąc pod uwagę zasady C #? Zobacz moją odpowiedź poniżej. B) Dlaczego został tak zaprojektowany? Prawdopodobnie tylko względy użyteczności, oparte na subiektywnych osądach dotyczących sposobu, w jaki większość ludzi używa liczb całkowitych i bajtów.
mqp
5

Ze specyfikacji języka C # 1.6.7.5 7.2.6.2 Binarne promocje numeryczne konwertuje oba operandy na int, jeśli nie można go dopasować do kilku innych kategorii. Domyślam się, że nie przeciążyli operatora +, aby przyjąć bajt jako parametr, ale chcą, aby działał nieco normalnie, więc po prostu używają typu danych int.

Język C # Spec

Ryan
źródło
4

Podejrzewam, że C # w rzeczywistości wywołuje operator+zdefiniowane int(co zwraca „ intchyba, że ​​jesteś w checkedbloku”) i pośrednio rzutuje oba twoje bytes/ shortsna ints. Dlatego zachowanie wydaje się niespójne.

mqp
źródło
3
Pcha oba bajty na stosie, a następnie wywołuje polecenie „dodaj”. W IL dodaj „zjada” dwie wartości i zastąp je int.
Jonathan Allen,
3

Prawdopodobnie była to praktyczna decyzja projektantów języków. W końcu int to Int32, 32-bitowa liczba całkowita ze znakiem. Ilekroć wykonujesz operację na liczbach całkowitych na typie mniejszym niż int, i tak zostanie ona przekonwertowana na 32-bitowy znak int przez większość dowolnego 32-bitowego procesora. To, w połączeniu z prawdopodobieństwem przepełnienia małych liczb całkowitych, prawdopodobnie przypieczętowało umowę. Pozwala to uniknąć ciągłego sprawdzania przekroczenia / niedopełnienia, a gdy końcowy wynik wyrażenia w bajtach będzie w zakresie, pomimo faktu, że na pewnym etapie pośrednim będzie poza zakresem, otrzymasz poprawną wynik.

Inna myśl: należałoby zasymulować przekroczenie / niedopełnienie tych typów, ponieważ nie wystąpiłoby to naturalnie na najbardziej prawdopodobnych docelowych procesorach. Po co się męczyć?

PeterAllenWebb
źródło
2

Jest to w przeważającej części moja odpowiedź na ten temat, postawiona najpierw na podobne pytanie tutaj .

Wszystkie operacje z liczbami całkowitymi mniejszymi niż Int32 są domyślnie zaokrąglane w górę do 32 bitów przed obliczeniem. Powodem, dla którego wynikiem jest Int32, jest po prostu pozostawienie go takim, jakim jest po obliczeniach. Jeśli zaznaczysz arytmetyczne kody MSIL, jedynym integralnym typem numerycznym, z którym działają, są Int32 i Int64. To „z założenia”.

Jeśli chcesz uzyskać wynik w formacie Int16, nie ma znaczenia, czy wykonasz rzutowanie kodu, czy kompilator (hipotetycznie) wyśle ​​konwersję „pod maską”.

Na przykład, aby wykonać arytmetykę Int16:

short a = 2, b = 3;

short c = (short) (a + b);

Dwie liczby rozszerzyłyby się do 32 bitów, zostaną dodane, a następnie skrócone z powrotem do 16 bitów, tak właśnie planowało to MS.

Zaletą korzystania z krótkich (lub bajtów) jest przede wszystkim przechowywanie w przypadkach, gdy masz ogromne ilości danych (dane graficzne, przesyłanie strumieniowe itp.)

Kenan EK
źródło
1

Dodawanie nie jest zdefiniowane dla bajtów. Więc są dodawane do int dla dodania. Dotyczy to większości operacji matematycznych i bajtów. (zwróć uwagę, że tak było kiedyś w starszych językach, zakładam, że tak jest dzisiaj).

Jim C.
źródło
0

Myślę, że jest to decyzja projektowa o tym, która operacja była bardziej powszechna ... Jeśli bajt + bajt = bajt, być może znacznie więcej osób będzie się przejmować koniecznością rzutowania na int, gdy wynik jest wymagany.

fortran
źródło
2
Raz mi przeszkadzało w drugą stronę :) Zawsze wydaje mi się, że potrzebuję wyniku bajtu, więc zawsze muszę przesyłać.
Roman Starkov
Tyle że nie musisz rzutować na int. Obsada jest niejawna. Tylko inny sposób jest wyraźny.
Niki,
1
@nikie Myślę, że nie zrozumiałeś mojej odpowiedzi. Jeśli dodanie dwóch bajtów wytworzy bajt, aby zapobiec przepełnieniu, ktoś będzie musiał rzucić operandy (nie wynik) na int przed dodaniem.
fortran
0

Z kodu .NET Framework:

// bytes
private static object AddByte(byte Left, byte Right)
{
    short num = (short) (Left + Right);
    if (num > 0xff)
    {
        return num;
    }
    return (byte) num;
}

// shorts (int16)
private static object AddInt16(short Left, short Right)
{
    int num = Left + Right;
    if ((num <= 0x7fff) && (num >= -32768))
    {
        return (short) num;
    }
    return num;
}

Uprość dzięki .NET 3.5 i nowszym:

public static class Extensions 
{
    public static byte Add(this byte a, byte b)
    {
        return (byte)(a + b);
    }
}

teraz możesz zrobić:

byte a = 1, b = 2, c;
c = a.Add(b);

serhio
źródło
0

Testowałem wydajność między bajtem a liczbą całkowitą.
Z wartościami int:

class Program
{
    private int a,b,c,d,e,f;

    public Program()
    {
        a = 1;
        b = 2;
        c = (a + b);
        d = (a - b);
        e = (b / a);
        f = (c * b);
    }

    static void Main(string[] args)
    {
        int max = 10000000;
        DateTime start = DateTime.Now;
        Program[] tab = new Program[max];

        for (int i = 0; i < max; i++)
        {
            tab[i] = new Program();
        }
        DateTime stop = DateTime.Now;

        Debug.WriteLine(stop.Subtract(start).TotalSeconds);
    }
}

Z wartościami bajtów:

class Program
{
    private byte a,b,c,d,e,f;

    public Program()
    {
        a = 1;
        b = 2;
        c = (byte)(a + b);
        d = (byte)(a - b);
        e = (byte)(b / a);
        f = (byte)(c * b);
    }

    static void Main(string[] args)
    {
        int max = 10000000;
        DateTime start = DateTime.Now;
        Program[] tab = new Program[max];

        for (int i = 0; i < max; i++)
        {
            tab[i] = new Program();
        }
        DateTime stop = DateTime.Now;

        Debug.WriteLine(stop.Subtract(start).TotalSeconds);
    }
}

Oto wynik:
bajt: 3,57s 157mo, 3,71s 171mo, 3,74s 168mo z procesorem ~ = 30%
int: 4,05s 298mo, 3,92s 278mo, 4,28 294mo z procesorem ~ = 27%
Wniosek:
bajt używa więcej procesora, ale kosztuje mniej pamięci i jest szybszy (być może dlatego, że do przydzielenia jest mniej bajtów)

puipuix
źródło
-1

Oprócz wszystkich innych świetnych komentarzy, pomyślałem, że dodam jeszcze jeden mały smakołyk. Wiele komentarzy zastanawiało się, dlaczego int, long i właściwie jakikolwiek inny typ liczbowy również nie przestrzega tej zasady ... zwraca „większy” typ w odpowiedzi na arytmatykę.

Wiele odpowiedzi miało związek z wydajnością (cóż, 32 bity są szybsze niż 8 bitów). W rzeczywistości liczba 8-bitowa jest nadal liczbą 32-bitową w procesorze 32-bitowym .... nawet jeśli dodasz dwa bajty, część danych, na których działa procesor, będzie 32-bitowa niezależnie od tego ... więc dodanie ints nie będzie być „szybszym” niż dodawanie dwóch bajtów ... to wszystko to samo dla procesora. TERAZ dodanie dwóch liczb wewnętrznych BĘDZIE szybsze niż dodanie dwóch długich sekwencji na 32-bitowym procesorze, ponieważ dodanie dwóch długich wymaga więcej mikroprocesorów, ponieważ pracujesz z liczbami szerszymi niż słowo procesorów.

Myślę, że podstawowy powód spowodowania, że ​​arytmetyka bajtów powoduje ints, jest dość jasny i prosty: 8 bitów po prostu nie idzie bardzo daleko! : D Przy 8 bitach masz niepodpisany zakres 0-255. To nie jest dużo miejsca do pracy ... prawdopodobieństwo, że napotkasz ograniczenia bajtów, jest BARDZO wysokie, gdy używasz ich w arytmetyce. Jednak szansa, że ​​zabraknie Ci bitów podczas pracy z intami, długimi, podwójnymi itp. Jest znacznie niższa ... wystarczająco niska, że ​​bardzo rzadko spotykamy się z potrzebą więcej.

Automatyczna konwersja z bajtu na int jest logiczna, ponieważ skala bajtu jest tak mała. Automatyczna konwersja z int na long, float na double itp. Nie jest logiczna, ponieważ liczby te mają znaczną skalę.

jrista
źródło
To wciąż nie wyjaśnia, dlaczego byte - bytepowraca intani dlaczego nie rzuca na short...
KthProg
Dlaczego chcesz, aby dodawanie zwracało inny typ niż odejmowanie? Jeśli byte + bytezwraca int, ponieważ 255 + cokolwiek jest większe niż bajt może pomieścić, nie ma sensu, aby jakikolwiek bajt minus jakikolwiek inny bajt zwracał coś innego niż int z punktu widzenia spójności typu zwracanego.
jrista
Nie zrobiłbym tego, to po prostu pokazuje, że powyższy powód jest prawdopodobnie niewłaściwy. Gdyby miało to związek z „dopasowaniem” do wyniku, byteodejmowanie zwróciłoby a byte, a dodanie bajtu zwróciłoby a short( byte+ bytezawsze będzie pasować do a short). Gdyby chodziło o spójność, jak mówisz, to shortnadal wystarczyłoby dla obu operacji, a nie int. Oczywiście jest wiele przyczyn, nie wszystkie z nich muszą być dobrze przemyślane. Lub podany poniżej powód wydajności może być dokładniejszy.
KthProg,