[этюд (обновление)] int uint -- что там внутри
От: 0K Ниоткуда  
Дата: 22.07.10 13:11
Оценка:
Прошу прощения, приходится обновлять этюд http://rsdn.ru/forum/dotnet/3888666.flat.aspx
Автор: 0K
Дата: 22.07.10
(в первой версии была допущена ошибка)

Итак, теперь классы выглядят таким образом:

public class Paranja1
{
    uint _a;
    uint _b;

    public int A
    {
        get
        {
            return (int)_a;
        }
        set
        {
            _a = (uint)value;
        }
    }

    public int B
    {
        get
        {
            return (int)_b;
        }
        set
        {
            _b = (uint)value;
        }
    }

    public void Add()
    {
        _a += _b;
    }

    public void Sub()
    {
        _a -= _b;
    }

    public void Mul()
    {
        _a *= _b;
    }

    public void Div()
    {
        _a *= _b;
    }

    public void Left()
    {
        _a = _a << (int)_b;
    }

    public void Right()
    {
        _a = _a >> (int)_b;
    }
}

public class Paranja2
{
    public int A
    {
        get;
        set;
    }

    public int B
    {
        get;
        set;
    }

    public void Add()
    {
        A += B;
    }

    public void Sub()
    {
        A -= B;
    }

    public void Mul()
    {
        A *= B;
    }

    public void Div()
    {
        A *= B;
    }

    public void Left()
    {
        A = A << (int)B;
    }

    public void Right()
    {
        A = A >> (int)B;
    }
}



Как теперь определить какой тип имеют закрытые поля?
Re: [этюд (обновление)] int uint -- что там внутри
От: 0K Ниоткуда  
Дата: 22.07.10 13:25
Оценка:
Здравствуйте, 0K, Вы писали:

0K>Итак, теперь классы выглядят таким образом:


Кому интересно, еще расширил (ниже). Но и в первом варианте есть как минимум одна возможность определить тип чисто арифметически.

Вот вариант со всеми возможными операциями. Как минимум одна операция дает сбой (т.е. разница между int и uint).

public class Paranja1
{
    uint _a;
    uint _b;

    public int A
    {
        get
        {
            return (int)_a;
        }
        set
        {
            _a = (uint)value;
        }
    }

    public int B
    {
        get
        {
            return (int)_b;
        }
        set
        {
            _b = (uint)value;
        }
    }

    public void Add()
    {
        _a += _b;
    }

    public void Sub()
    {
        _a -= _b;
    }

    public void Mul()
    {
        _a *= _b;
    }

    public void Div()
    {
        _a *= _b;
    }

    public void Left()
    {
        _a = _a << (int)_b;
    }

    public void Right()
    {
        _a = _a >> (int)_b;
    }

    public void Dec()
    {
        _a = ~_a;
    }

    public void And()
    {
        _a = _a & _b;
    }

    public void Or()
    {
        _a = _a | _b;
    }

    public void Xor()
    {
        _a = _a ^ _b;
    }
}

public class Paranja2
{
    int _a;
    int _b;

    public int A
    {
        get
        {
            return _a;
        }
        set
        {
            _a = value;
        }
    }

    public int B
    {
        get
        {
            return _b;
        }
        set
        {
            _b = value;
        }
    }

    public void Add()
    {
        _a += _b;
    }

    public void Sub()
    {
        _a -= _b;
    }

    public void Mul()
    {
        _a *= _b;
    }

    public void Div()
    {
        _a *= _b;
    }

    public void Left()
    {
        _a = _a << (int)_b;
    }

    public void Right()
    {
        _a = _a >> (int)_b;
    }

    public void Dec()
    {
        _a = ~_a;
    }

    public void And()
    {
        _a = _a & _b;
    }

    public void Or()
    {
        _a = _a | _b;
    }

    public void Xor()
    {
        _a = _a ^ _b;
    }
}
Re: [этюд (обновление)] int uint -- что там внутри
От: 0K Ниоткуда  
Дата: 22.07.10 13:52
Оценка:
Здравствуйте, 0K, Вы писали:

0K>Прошу прощения, приходится обновлять этюд http://rsdn.ru/forum/dotnet/3888666.flat.aspx
Автор: 0K
Дата: 22.07.10
(в первой версии была допущена ошибка)


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

Но все-же есть одна (как минимум одна, больше пока не нашел) тонкость, о которой знают либо очень дотошные люди (которые, видимо, понимают все тонкости работы процессора) либо кто столкнулся на практике. К примеру программисты MainSoft, которые сделали переводчик Grasshopper MSIL->Java об этом не знают и их переводчик падает на этой фишке.
Re: [этюд (обновление)] int uint -- что там внутри
От: Niswn  
Дата: 22.07.10 13:56
Оценка: 6 (1) +1
Здравствуйте, 0K, Вы писали:

0K>
0K>public class Paranja1
0K>{
0K>    uint _a;
0K>    uint _b;
0K>    .....
0K>}

0K>public class Paranja2
0K>{
0K>    public int A
0K>    {
0K>        get;
0K>        set;
0K>    }

0K>    public int B
0K>    {
0K>        get;
0K>        set;
0K>    }
0K>    .......

0K>}
0K>



0K>Как теперь определить какой тип имеют закрытые поля?

Способы:
1. Самый наипростейший — посмотреть исходник
2. Воспользоваться сдвигом вправо с отрицательным A. При этом беззнаковое будет заполняться слева нулями, а знаковое еденицами. Пример:

Paranja1 par1 = new Paranja1();
            par1.A = -1;
            par1.B = 1;
            par1.Right(); //par1.A = 0x7fffffff
            Paranja2 par2 = new Paranja2();
            par2.A = -1;
            par2.B = 1;
            par2.Right(); //par2.A = 0xffffffff

3. Насколько я помню из универа, двоичные операции умножения и деления знаковых и беззнаковых чисел отличаются. То есть можно найти в инете алгоритм умножения скажем беззнаковых чисел с помощью операций сложения и сдвига, реализовать его с помощь методов класса, а потом сравнить с результатом выполнения метода Mul. Но это я не проверял.
ICQ: 326084932
Re[2]: [этюд (обновление)] int uint -- что там внутри
От: 0K Ниоткуда  
Дата: 22.07.10 14:06
Оценка:
Здравствуйте, Niswn, Вы писали:

N>1. Самый наипростейший — посмотреть исходник


Ну это не серьезно. Рефлексия и реверс запрещены (это в первый раз оговорил).

N>2. Воспользоваться сдвигом вправо с отрицательным A. При этом беззнаковое будет заполняться слева нулями, а знаковое еденицами. Пример:


Вот! Вы знали об этом, или только что проверили?

N>3. Насколько я помню из универа, двоичные операции умножения и деления знаковых и беззнаковых чисел отличаются. То есть можно найти в инете алгоритм умножения скажем беззнаковых чисел с помощью операций сложения и сдвига, реализовать его с помощь методов класса, а потом сравнить с результатом выполнения метода Mul. Но это я не проверял.


Кто знает подробнее?
Re[2]: [этюд (обновление)] int uint -- что там внутри
От: 0K Ниоткуда  
Дата: 22.07.10 14:11
Оценка:
Здравствуйте, Niswn, Вы писали:

N>3. Насколько я помню из универа, двоичные операции умножения и деления знаковых и беззнаковых чисел отличаются. То есть можно найти в инете алгоритм умножения скажем беззнаковых чисел с помощью операций сложения и сдвига, реализовать его с помощь методов класса, а потом сравнить с результатом выполнения метода Mul. Но это я не проверял.


Т.е. Mul и Div у обеих паранджей отличаться не будут? Будут только двоичные деления отличаться?

Тогда можно проще -- найти эту двоичную операции, после которой результат Parandja1 и Parandja2 будет отличаться. Скорее всего это и будет сдвиг.

И вопрос ко всем. Кроме сдвига есть еще какие-нибудь операции, дающие разный результат? Можно использовать все существующие операции с целыми числами: +-*/|&^~
Re[3]: [этюд (обновление)] int uint -- что там внутри
От: Niswn  
Дата: 22.07.10 14:21
Оценка:
Здравствуйте, 0K, Вы писали:

0K>Здравствуйте, Niswn, Вы писали:


N>>2. Воспользоваться сдвигом вправо с отрицательным A. При этом беззнаковое будет заполняться слева нулями, а знаковое еденицами. Пример:


0K>Вот! Вы знали об этом, или только что проверили?

Знал. Скорее даже не знал, а помнил с университетского курса. Это ж двоичная арифметика. Ну перед тем как запостить ответ конечно же проверил, а то вдруг процессоры теперь по другому считают.

N>>3. Насколько я помню из универа, двоичные операции умножения и деления знаковых и беззнаковых чисел отличаются. То есть можно найти в инете алгоритм умножения скажем беззнаковых чисел с помощью операций сложения и сдвига, реализовать его с помощь методов класса, а потом сравнить с результатом выполнения метода Mul. Но это я не проверял.


0K>Кто знает подробнее?

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

Кстати было у меня ещё такое предположение:
В классе с uint имеется доп. операция приведения типов. И я думал, что если в цикле 10000000 раз проинициализировать и прочитать содержимое свойств, то для разных классов будет разное время выполнения (для uint по идеи должно быть больше). Но на практике время почти не отличается. То есть эта операция приведения ничего не стоит получается.
ICQ: 326084932
Re[3]: [этюд (обновление)] int uint -- что там внутри
От: Niswn  
Дата: 22.07.10 14:30
Оценка:
Здравствуйте, 0K, Вы писали:

0K>Здравствуйте, Niswn, Вы писали:


N>>3. Насколько я помню из универа, двоичные операции умножения и деления знаковых и беззнаковых чисел отличаются. То есть можно найти в инете алгоритм умножения скажем беззнаковых чисел с помощью операций сложения и сдвига, реализовать его с помощь методов класса, а потом сравнить с результатом выполнения метода Mul. Но это я не проверял.


0K>Т.е. Mul и Div у обеих паранджей отличаться не будут? Будут только двоичные деления отличаться?

Конечно не будут.
Скорее всего будет отличаться только, если вы реализуете алгоритм умножения для беззнакового с помощью функций сложения/сдвига, а число окажется знаковым. Тогда вы просто получите неверный результат умножения. Ну я так предполагаю. Проверять времени нету.

0K>Тогда можно проще -- найти эту двоичную операции, после которой результат Parandja1 и Parandja2 будет отличаться. Скорее всего это и будет сдвиг.

Проще, но вы ж хотели все решения .

0K>И вопрос ко всем. Кроме сдвига есть еще какие-нибудь операции, дающие разный результат? Можно использовать все существующие операции с целыми числами: +-*/|&^~

Битовый операций кроме сдвига точно не дают различий. Операции сложения и вычитания тоже одинаковы для беззнаковых и знаковых чисел. Остается умножение/деление
ICQ: 326084932
Re[4]: [этюд (обновление)] int uint -- что там внутри
От: 0K Ниоткуда  
Дата: 22.07.10 15:01
Оценка:
Здравствуйте, Niswn, Вы писали:

0K>>И вопрос ко всем. Кроме сдвига есть еще какие-нибудь операции, дающие разный результат? Можно использовать все существующие операции с целыми числами: +-*/|&^~

N>Битовый операций кроме сдвига точно не дают различий. Операции сложения и вычитания тоже одинаковы для беззнаковых и знаковых чисел. Остается умножение/деление

А что умножение и деление? Разве есть разница?
j
Re: Signed overflow
От: SergeCpp Россия http://zoozahita.ru
Дата: 22.07.10 15:27
Оценка:
Здравствуйте, 0K!

Можно попробовать устроить signed overflow (max_signed_int + 1) и посмотреть:

Чтобы арифметические операции, операции приведения или преобразования вызывали OverflowException, операция должна проходить в проверяемом контексте.По умолчанию проверка арифметических операций и переполнения ведется только в Visual Basic; в C# они не проверяются по умолчанию. Если операция выполняется в непроверяемом контексте, результат усекается путем удаления старших разрядов, которые не помещаются в целевой тип данных.
http://msdn.microsoft.com/ru-ru/library/system.overflowexception.aspx

Вот тут ещё почитайте:
http://www.fefe.de/intof.html
http://zoozahita.ruБездомные животные Екатеринбурга ищут хозяев
Re[2]: Signed overflow
От: 0K Ниоткуда  
Дата: 22.07.10 15:40
Оценка:
Здравствуйте, SergeCpp, Вы писали:

SC>Здравствуйте, 0K!


SC>Можно попробовать устроить signed overflow (max_signed_int + 1) и посмотреть:


Не, не выйдет. Код в скомпиленной библиотеке и перекомпилить вы не можете.

Да и вообще -- здесь важно найти арифметическое решение, а не хитрости всякие ваши с временными технологиями, которые сегодня одни а завтра другие!

Про сдвиг читали (выше)? Теперь ищем вдруг еще какая-нибудь операция дает разницу. Получается только сдвиг вправо, остальное 100% идентично.
Re[3]: Signed overflow
От: Jolly Roger  
Дата: 22.07.10 16:40
Оценка:
Здравствуйте, 0K, Вы писали:

"Жениться. Вам, барин, надо"©

Когда я был молодым, высоким, кудрявым и красивым, а компьютеры были большими, единственным микропроцессором была реинкарнация i8080, гордо именовавшая себя 580ВМ80, и тогда каждый прогер должен был как "Отче наш" знать, что такое двоичное представление целого, дополнение до единицы, и какие бывают форматы представления чисел с плавающей запятой. Ну это было как-бы в базисе... А Вам оно зачем понадобилось?
"Нормальные герои всегда идут в обход!"
Re[4]: Signed overflow
От: 0K Ниоткуда  
Дата: 22.07.10 17:24
Оценка:
Здравствуйте, Jolly Roger, Вы писали:

JR>Когда я был молодым, высоким, кудрявым и красивым, а компьютеры были большими, единственным микропроцессором была реинкарнация i8080, гордо именовавшая себя 580ВМ80, и тогда каждый прогер должен был как "Отче наш" знать, что такое двоичное представление целого, дополнение до единицы, и какие бывают форматы представления чисел с плавающей запятой. Ну это было как-бы в базисе...


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

JR>А Вам оно зачем понадобилось?


Начал проверять программу Grasshopper (автоматический перевод MS IL -> Java). Т.к. в Java нет беззнаковых чесел -- там такой баг есть со сдвигами. Их программисты об этом просто не подумали за несколько лет создания программы.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.