Нашли или выдавили из себя код, который нельзя назвать нормальным,
на который без улыбки не взглянешь?
Не торопитесь его удалять или рефакторить, — запостите его на
говнокод.ру, посмеёмся вместе!
Жабовское байтоебство (судя по всему это такой ntohl) из реализации VNC.
Вот интересно, в жабке-то unsigned типов нет нихера, но почему-то сделали unsigned двоичный сдвиг (>>>), который работает для этих встроенных signed типов как если б это были unsigned. А как насчет unsigned умножения и деления (сложение и вычитание - то один хер, без разницы, если у нас two's complement)?
byte: The byte data type is an 8-bit signed two's complement integer. It has a minimum value of -128 and a maximum value of 127 (inclusive). The byte data type can be useful for saving memory in large arrays, where the memory savings actually matters. They can also be used in place of int where their limits help to clarify your code; the fact that a variable's range is limited can serve as a form of documentation.
short: The short data type is a 16-bit signed two's complement integer. It has a minimum value of -32,768 and a maximum value of 32,767 (inclusive). As with byte, the same guidelines apply: you can use a short to save memory in large arrays, in situations where the memory savings actually matters.
int: By default, the int data type is a 32-bit signed two's complement integer, which has a minimum value of -2^31 and a maximum value of 2^31-1. In Java SE 8 and later, you can use the int data type to represent an unsigned 32-bit integer, which has a minimum value of 0 and a maximum value of 2^32-1. Use the Integer class to use int data type as an unsigned integer. See the section The Number Classes for more information. Static methods like compareUnsigned, divideUnsigned etc have been added to the Integer class to support the arithmetic operations for unsigned integers.
long: The long data type is a 64-bit two's complement integer. The signed long has a minimum value of -2^63 and a maximum value of 2^63-1. In Java SE 8 and later, you can use the long data type to represent an unsigned 64-bit long, which has a minimum value of 0 and a maximum value of 2^64-1. Use this data type when you need a range of values wider than those provided by int. The Long class also contains methods like compareUnsigned, divideUnsigned etc to support arithmetic operations for unsigned long.
Почему-то добавили только в Java SE 8 и то не для всех базовых целочисленных типов (byte и short они решили зачем-то не трогать). И добавили они это через какие-то классы-хуяссы.
Вычисления идут с интами, но результат потом подрезается. Но, поскольку signed переполнение это UB, а для unsigned всё выглядит как-будто складывали байты, то ты не заметишь подвоха.
Интересно, зачем тогда вообще это правило про каст мелочи в int перед операциями? Оно же как чайник Рассела. Ни доказать ни опровергнуть.
Допустим, нужно перемножить два signed, а у нас только беззнаковое умножение:
Пусть x_u, y_u –— временные беззнаковые переменные (типа uint16_t), хранящие битовые копии x, y (типа int16_t).
Тогда x_u = x + pow(2,16)*h(x<0), где h –— функция Хевисайда;
y_u = y + pow(2,16)*h(y<0);
x_u*y_u = x*y + pow(2,16)*(y*h(x<0) + x*h(y<0)) + pow(2,32)*h(x<0)*h(y<0).
Выразим x и y через x_u и y_u соответственно и найдём значение x*y через беззнаковые переменные:
x*y = x_u*y_u - pow(2,16)*(y_u*h(x<0) + x_u*h(y<0)) +
+ pow(2,32)*h(x<0)*h(y<0)*(-1 + 1 + 1).
От последнего слагаемого толку нет, ибо его значение за пределом разрядности.
А теперь если наоборот, у нас только знаковое умножение.
Пусть x_s, y_s –— временные знаковые переменные (типа int16_t), хранящие копии x,y (типа uint16_t).
Тогда x_s = x - pow(2,16)*h(x>T-1);
y_s = y - pow(2,16)*h(y>T-1);
где T = pow(2,15) –— постоянная Тараса для данного типа данных.
x_s*y_s = x*y - pow(2,16)*(y*h(x>T-1) + x*h(y>T-1)) + pow(2,32)*h(x>T-1)*h(y>T-1).
Аналогично выразим x и y через x_s и y_s и получим:
x*y = x_s*y_s + pow(2,16)*(y_s*h(x>T-1) + x_s*h(y>T-1)) + pow(2,32)*h(x>T-1)*h(y>T-1)*(-1+1+1).
Ну всмысле до умножения что-то простое (знаковый бит выбить?) и после умножения что-то настолько же простое. Чтобы x и y участвовали только по одному разу.
А в ваших "крестах" (или где-нибудь ещо) есть нечто для объявления типа такого: функция принимает параметр какого-нибудь челочисленного типа, а результат целочисленный с разрядностью в 2 раза больше чем у параметра? (ну кароч тип результата зависит от типа пораметра)
Если у нас есть знаковые int32_t, и надо перемножить их как беззнаковые, и при этом нам доступно умножение через более широкие знаковые, например int64_t, то всё вообще очень просто.
Кстати, а можно как-то протаскивать carry flag между блоками ассемблера? А то можно было бы написать рекурсивный темплейт, который раскрывается в цепочку adc нужной длины...
Ты злой. Это от отсутствия темплейтов. Я пишу только на темплейтах и чувствую себя замечательно! Попробуй и ты вычислить траекторию полёта ракеты на Марс в компайл-тайме!
int main(){
for (int i = -32768; i <= 32767; i++)
for (int j = i; j <= 32767; j++) {
int a = i * j;
int b = (int)(((unsigned)i) * (unsigned)j);
if (a != b)
printf("%d * %d = %d != %d\n", i, j, a, b);
}
puts("done.");
return 0;
}
Это наверное синтаксис «AT&T». Суффикс «l» означает, что аргумент размером в двойное слово. Регистр ebx как раз подходит, только в «AT&T» он пишется с префиксом «%»:
osyol %ebx
А если будешь использовать встроенный ассемблер в «gcc» или в «clang», то знак «%» ещё нужно удвоить, чтобы по ошибке не подставился мокрос.
Это даже на хардварная многозадачность с её джампами в другие сегменты через гейнты (кто вообще эту хуйню помнит?!) а просто какой-то хардварный шедулер
А что такого? В видюхах например стоят аппаратные шедулеры, которые тысячи тредов могут обслуживать. Но там с переключением совсем просто - у каждого треда свои регистры.
byte: The byte data type is an 8-bit signed two's complement integer. It has a minimum value of -128 and a maximum value of 127 (inclusive). The byte data type can be useful for saving memory in large arrays, where the memory savings actually matters. They can also be used in place of int where their limits help to clarify your code; the fact that a variable's range is limited can serve as a form of documentation.
short: The short data type is a 16-bit signed two's complement integer. It has a minimum value of -32,768 and a maximum value of 32,767 (inclusive). As with byte, the same guidelines apply: you can use a short to save memory in large arrays, in situations where the memory savings actually matters.
int: By default, the int data type is a 32-bit signed two's complement integer, which has a minimum value of -2^31 and a maximum value of 2^31-1. In Java SE 8 and later, you can use the int data type to represent an unsigned 32-bit integer, which has a minimum value of 0 and a maximum value of 2^32-1. Use the Integer class to use int data type as an unsigned integer. See the section The Number Classes for more information. Static methods like compareUnsigned, divideUnsigned etc have been added to the Integer class to support the arithmetic operations for unsigned integers.
long: The long data type is a 64-bit two's complement integer. The signed long has a minimum value of -2^63 and a maximum value of 2^63-1. In Java SE 8 and later, you can use the long data type to represent an unsigned 64-bit long, which has a minimum value of 0 and a maximum value of 2^64-1. Use this data type when you need a range of values wider than those provided by int. The Long class also contains methods like compareUnsigned, divideUnsigned etc to support arithmetic operations for unsigned long.
__m128i _mm_add_epi8 (__m128i a, __m128i b)
Интересно, зачем тогда вообще это правило про каст мелочи в int перед операциями? Оно же как чайник Рассела. Ни доказать ни опровергнуть.
uint8_t in[8];
uint16_t out[4];
out[0] = in[0] * in[1];
out[1] = in[2] * in[3];
out[2] = in[4] * in[5];
out[3] = in[6] * in[7];
Эмуляция через signed чтобы не трогать JVM?
Пусть x_u, y_u –— временные беззнаковые переменные (типа uint16_t), хранящие битовые копии x, y (типа int16_t).
Тогда x_u = x + pow(2,16)*h(x<0), где h –— функция Хевисайда;
y_u = y + pow(2,16)*h(y<0);
x_u*y_u = x*y + pow(2,16)*(y*h(x<0) + x*h(y<0)) + pow(2,32)*h(x<0)*h(y<0).
Выразим x и y через x_u и y_u соответственно и найдём значение x*y через беззнаковые переменные:
x*y = x_u*y_u - pow(2,16)*(y_u*h(x<0) + x_u*h(y<0)) +
+ pow(2,32)*h(x<0)*h(y<0)*(-1 + 1 + 1).
От последнего слагаемого толку нет, ибо его значение за пределом разрядности.
Итого:
https://ideone.com/DDqPGb
Теперь всё правильно:
https://ideone.com/7TE4No
Пусть x_s, y_s –— временные знаковые переменные (типа int16_t), хранящие копии x,y (типа uint16_t).
Тогда x_s = x - pow(2,16)*h(x>T-1);
y_s = y - pow(2,16)*h(y>T-1);
где T = pow(2,15) –— постоянная Тараса для данного типа данных.
x_s*y_s = x*y - pow(2,16)*(y*h(x>T-1) + x*h(y>T-1)) + pow(2,32)*h(x>T-1)*h(y>T-1).
Аналогично выразим x и y через x_s и y_s и получим:
x*y = x_s*y_s + pow(2,16)*(y_s*h(x>T-1) + x_s*h(y>T-1)) + pow(2,32)*h(x>T-1)*h(y>T-1)*(-1+1+1).
https://ideone.com/hinhoN
Но тогда придётся x1.s и y1.s предварительно кастануть в числа вдвое большей разрядности.
ЩЫ. это не лисп, я прост пероритеты забуа
Вроде раьотает.
T + T = 0 (по модулю 2 в степени n).
Или так:
T = -T (по модулю 2 в степени n).
хотя тут могут быть ньюансы с endian
На темплейтах, чтобы конпелятор мог оптимизнуть под конкретную длину?
А если будешь использовать встроенный ассемблер в «gcc» или в «clang», то знак «%» ещё нужно удвоить, чтобы по ошибке не подставился мокрос.
Это даже на хардварная многозадачность с её джампами в другие сегменты через гейнты (кто вообще эту хуйню помнит?!) а просто какой-то хардварный шедулер
Ну иначе байтоёбить было бы совсем уныло.