Не понимаю 60 * 1000 != 60000?
- Войдите на сайт для отправки комментариев
Пт, 13/11/2015 - 22:38
Привет!
Странный на первый взгляд вопрос. Но у меня не получается 60000 при умножении 60 на 1000 ....
Типы вроде все вмещают, но результат странный...
0x0 | 0 * 1000 = 0 0x1 | 1 * 1000 = 1000 0x2 | 2 * 1000 = 2000 0x3 | 3 * 1000 = 3000 0x4 | 4 * 1000 = 4000 0x5 | 5 * 1000 = 5000 0x6 | 6 * 1000 = 6000 0x7 | 7 * 1000 = 7000 0x8 | 8 * 1000 = 8000 0x9 | 9 * 1000 = 9000 0xA | 10 * 1000 = 10000 0xB | 11 * 1000 = 11000 0xC | 12 * 1000 = 12000 0xD | 13 * 1000 = 13000 0xE | 14 * 1000 = 14000 0xF | 15 * 1000 = 15000 0x10 | 16 * 1000 = 16000 0x11 | 17 * 1000 = 17000 0x12 | 18 * 1000 = 18000 0x13 | 19 * 1000 = 19000 0x14 | 20 * 1000 = 20000 0x15 | 21 * 1000 = 21000 0x16 | 22 * 1000 = 22000 0x17 | 23 * 1000 = 23000 0x18 | 24 * 1000 = 24000 0x19 | 25 * 1000 = 25000 0x1A | 26 * 1000 = 26000 0x1B | 27 * 1000 = 27000 0x1C | 28 * 1000 = 28000 0x1D | 29 * 1000 = 29000 0x1E | 30 * 1000 = 30000 0x1F | 31 * 1000 = 31000 0x20 | 32 * 1000 = 32000 0x21 | 33 * 1000 = -32536 0x22 | 34 * 1000 = -31536 0x23 | 35 * 1000 = -30536 0x24 | 36 * 1000 = -29536 0x25 | 37 * 1000 = -28536 0x26 | 38 * 1000 = -27536 0x27 | 39 * 1000 = -26536 0x28 | 40 * 1000 = -25536 0x29 | 41 * 1000 = -24536 0x2A | 42 * 1000 = -23536 0x2B | 43 * 1000 = -22536 0x2C | 44 * 1000 = -21536 0x2D | 45 * 1000 = -20536 0x2E | 46 * 1000 = -19536 0x2F | 47 * 1000 = -18536 0x30 | 48 * 1000 = -17536 0x31 | 49 * 1000 = -16536 0x32 | 50 * 1000 = -15536 0x33 | 51 * 1000 = -14536 0x34 | 52 * 1000 = -13536 0x35 | 53 * 1000 = -12536 0x36 | 54 * 1000 = -11536 0x37 | 55 * 1000 = -10536 0x38 | 56 * 1000 = -9536 0x39 | 57 * 1000 = -8536 0x3A | 58 * 1000 = -7536 0x3B | 59 * 1000 = -6536 0x3C | 60 * 1000 = -5536 0x3D | 61 * 1000 = -4536 0x3E | 62 * 1000 = -3536 0x3F | 63 * 1000 = -2536 0x40 | 64 * 1000 = -1536 0x41 | 65 * 1000 = -536 0x42 | 66 * 1000 = 464 0x43 | 67 * 1000 = 1464 0x44 | 68 * 1000 = 2464 0x45 | 69 * 1000 = 3464 0x46 | 70 * 1000 = 4464 0x47 | 71 * 1000 = 5464 0x48 | 72 * 1000 = 6464 0x49 | 73 * 1000 = 7464 0x4A | 74 * 1000 = 8464 0x4B | 75 * 1000 = 9464 0x4C | 76 * 1000 = 10464 0x4D | 77 * 1000 = 11464 0x4E | 78 * 1000 = 12464 0x4F | 79 * 1000 = 13464 0x50 | 80 * 1000 = 14464 0x51 | 81 * 1000 = 15464 0x52 | 82 * 1000 = 16464 0x53 | 83 * 1000 = 17464 0x54 | 84 * 1000 = 18464 0x55 | 85 * 1000 = 19464 0x56 | 86 * 1000 = 20464 0x57 | 87 * 1000 = 21464 0x58 | 88 * 1000 = 22464 0x59 | 89 * 1000 = 23464 0x5A | 90 * 1000 = 24464 0x5B | 91 * 1000 = 25464 0x5C | 92 * 1000 = 26464 0x5D | 93 * 1000 = 27464 0x5E | 94 * 1000 = 28464 0x5F | 95 * 1000 = 29464 0x60 | 96 * 1000 = 30464 0x61 | 97 * 1000 = 31464 0x62 | 98 * 1000 = 32464 0x63 | 99 * 1000 = -32072 0x64 | 100 * 1000 = -31072 0x65 | 101 * 1000 = -30072 0x66 | 102 * 1000 = -29072 0x67 | 103 * 1000 = -28072 0x68 | 104 * 1000 = -27072 0x69 | 105 * 1000 = -26072 0x6A | 106 * 1000 = -25072 0x6B | 107 * 1000 = -24072 0x6C | 108 * 1000 = -23072 0x6D | 109 * 1000 = -22072 0x6E | 110 * 1000 = -21072 0x6F | 111 * 1000 = -20072 0x70 | 112 * 1000 = -19072 0x71 | 113 * 1000 = -18072 0x72 | 114 * 1000 = -17072 0x73 | 115 * 1000 = -16072 0x74 | 116 * 1000 = -15072 0x75 | 117 * 1000 = -14072 0x76 | 118 * 1000 = -13072 0x77 | 119 * 1000 = -12072 0x78 | 120 * 1000 = -11072 0x79 | 121 * 1000 = -10072 0x7A | 122 * 1000 = -9072 0x7B | 123 * 1000 = -8072 0x7C | 124 * 1000 = -7072 0x7D | 125 * 1000 = -6072 0x7E | 126 * 1000 = -5072 0x7F | 127 * 1000 = -4072 0xFFFFFF80 | -128 * 1000 = 3072 0xFFFFFF81 | -127 * 1000 = 4072 0xFFFFFF82 | -126 * 1000 = 5072 0xFFFFFF83 | -125 * 1000 = 6072 0xFFFFFF84 | -124 * 1000 = 7072 0xFFFFFF85 | -123 * 1000 = 8072 0xFFFFFF86 | -122 * 1000 = 9072 0xFFFFFF87 | -121 * 1000 = 10072 0xFFFFFF88 | -120 * 1000 = 11072 0xFFFFFF89 | -119 * 1000 = 12072 0xFFFFFF8A | -118 * 1000 = 13072 0xFFFFFF8B | -117 * 1000 = 14072 0xFFFFFF8C | -116 * 1000 = 15072 0xFFFFFF8D | -115 * 1000 = 16072 0xFFFFFF8E | -114 * 1000 = 17072 0xFFFFFF8F | -113 * 1000 = 18072 0xFFFFFF90 | -112 * 1000 = 19072 0xFFFFFF91 | -111 * 1000 = 20072 0xFFFFFF92 | -110 * 1000 = 21072 0xFFFFFF93 | -109 * 1000 = 22072 0xFFFFFF94 | -108 * 1000 = 23072 0xFFFFFF95 | -107 * 1000 = 24072 0xFFFFFF96 | -106 * 1000 = 25072 0xFFFFFF97 | -105 * 1000 = 26072 0xFFFFFF98 | -104 * 1000 = 27072 0xFFFFFF99 | -103 * 1000 = 28072 0xFFFFFF9A | -102 * 1000 = 29072 0xFFFFFF9B | -101 * 1000 = 30072 0xFFFFFF9C | -100 * 1000 = 31072 0xFFFFFF9D | -99 * 1000 = 32072 0xFFFFFF9E | -98 * 1000 = -32464 0xFFFFFF9F | -97 * 1000 = -31464 0xFFFFFFA0 | -96 * 1000 = -30464 0xFFFFFFA1 | -95 * 1000 = -29464 0xFFFFFFA2 | -94 * 1000 = -28464 0xFFFFFFA3 | -93 * 1000 = -27464 0xFFFFFFA4 | -92 * 1000 = -26464 0xFFFFFFA5 | -91 * 1000 = -25464 0xFFFFFFA6 | -90 * 1000 = -24464 0xFFFFFFA7 | -89 * 1000 = -23464 0xFFFFFFA8 | -88 * 1000 = -22464 0xFFFFFFA9 | -87 * 1000 = -21464 0xFFFFFFAA | -86 * 1000 = -20464 0xFFFFFFAB | -85 * 1000 = -19464 0xFFFFFFAC | -84 * 1000 = -18464 0xFFFFFFAD | -83 * 1000 = -17464 0xFFFFFFAE | -82 * 1000 = -16464 0xFFFFFFAF | -81 * 1000 = -15464 0xFFFFFFB0 | -80 * 1000 = -14464 0xFFFFFFB1 | -79 * 1000 = -13464 0xFFFFFFB2 | -78 * 1000 = -12464 0xFFFFFFB3 | -77 * 1000 = -11464 0xFFFFFFB4 | -76 * 1000 = -10464 0xFFFFFFB5 | -75 * 1000 = -9464 0xFFFFFFB6 | -74 * 1000 = -8464 0xFFFFFFB7 | -73 * 1000 = -7464 0xFFFFFFB8 | -72 * 1000 = -6464 0xFFFFFFB9 | -71 * 1000 = -5464 0xFFFFFFBA | -70 * 1000 = -4464 0xFFFFFFBB | -69 * 1000 = -3464 0xFFFFFFBC | -68 * 1000 = -2464 0xFFFFFFBD | -67 * 1000 = -1464 0xFFFFFFBE | -66 * 1000 = -464 0xFFFFFFBF | -65 * 1000 = 536 0xFFFFFFC0 | -64 * 1000 = 1536 0xFFFFFFC1 | -63 * 1000 = 2536 0xFFFFFFC2 | -62 * 1000 = 3536 0xFFFFFFC3 | -61 * 1000 = 4536 0xFFFFFFC4 | -60 * 1000 = 5536 0xFFFFFFC5 | -59 * 1000 = 6536 0xFFFFFFC6 | -58 * 1000 = 7536 0xFFFFFFC7 | -57 * 1000 = 8536 0xFFFFFFC8 | -56 * 1000 = 9536 0xFFFFFFC9 | -55 * 1000 = 10536 0xFFFFFFCA | -54 * 1000 = 11536 0xFFFFFFCB | -53 * 1000 = 12536 0xFFFFFFCC | -52 * 1000 = 13536 0xFFFFFFCD | -51 * 1000 = 14536 0xFFFFFFCE | -50 * 1000 = 15536 0xFFFFFFCF | -49 * 1000 = 16536 0xFFFFFFD0 | -48 * 1000 = 17536 0xFFFFFFD1 | -47 * 1000 = 18536 0xFFFFFFD2 | -46 * 1000 = 19536 0xFFFFFFD3 | -45 * 1000 = 20536 0xFFFFFFD4 | -44 * 1000 = 21536 0xFFFFFFD5 | -43 * 1000 = 22536 0xFFFFFFD6 | -42 * 1000 = 23536 0xFFFFFFD7 | -41 * 1000 = 24536 0xFFFFFFD8 | -40 * 1000 = 25536 0xFFFFFFD9 | -39 * 1000 = 26536 0xFFFFFFDA | -38 * 1000 = 27536 0xFFFFFFDB | -37 * 1000 = 28536 0xFFFFFFDC | -36 * 1000 = 29536 0xFFFFFFDD | -35 * 1000 = 30536 0xFFFFFFDE | -34 * 1000 = 31536 0xFFFFFFDF | -33 * 1000 = 32536 0xFFFFFFE0 | -32 * 1000 = -32000 0xFFFFFFE1 | -31 * 1000 = -31000 0xFFFFFFE2 | -30 * 1000 = -30000 0xFFFFFFE3 | -29 * 1000 = -29000 0xFFFFFFE4 | -28 * 1000 = -28000 0xFFFFFFE5 | -27 * 1000 = -27000 0xFFFFFFE6 | -26 * 1000 = -26000 0xFFFFFFE7 | -25 * 1000 = -25000 0xFFFFFFE8 | -24 * 1000 = -24000 0xFFFFFFE9 | -23 * 1000 = -23000 0xFFFFFFEA | -22 * 1000 = -22000 0xFFFFFFEB | -21 * 1000 = -21000 0xFFFFFFEC | -20 * 1000 = -20000 0xFFFFFFED | -19 * 1000 = -19000 0xFFFFFFEE | -18 * 1000 = -18000 0xFFFFFFEF | -17 * 1000 = -17000 0xFFFFFFF0 | -16 * 1000 = -16000 0xFFFFFFF1 | -15 * 1000 = -15000 0xFFFFFFF2 | -14 * 1000 = -14000 0xFFFFFFF3 | -13 * 1000 = -13000 0xFFFFFFF4 | -12 * 1000 = -12000 0xFFFFFFF5 | -11 * 1000 = -11000 0xFFFFFFF6 | -10 * 1000 = -10000 0xFFFFFFF7 | -9 * 1000 = -9000 0xFFFFFFF8 | -8 * 1000 = -8000 0xFFFFFFF9 | -7 * 1000 = -7000 0xFFFFFFFA | -6 * 1000 = -6000 0xFFFFFFFB | -5 * 1000 = -5000 0xFFFFFFFC | -4 * 1000 = -4000 0xFFFFFFFD | -3 * 1000 = -3000 0xFFFFFFFE | -2 * 1000 = -2000 0xFFFFFFFF | -1 * 1000 = -1000
Вот скетч, который это выдаёт:
int8_t b = 0x00; void setup() { // put your setup code here, to run once: Serial.begin(9600); } void loop() { long ul = 0; ul = b * 1000; Serial.print("0x"); Serial.print(b, HEX); Serial.print(" | "); Serial.print(b); Serial.print(" * 1000 = "); Serial.println(ul); b++; delay(100); }
Первый раз такое вижу... Что я не доучил?
Вот так всегда... Стоит задать вопрос как ответ тут же будет найден самостоятельно.
Вопрос снят. Решение оказалось не очевидным. Компилятору нужно сказать что в результате действия я намерен получить long. Сам он видимо не понимает.
Сначала производится умножение, а уже потом полученное значение приводится к long.
b - 8 бит со знаком, 1000 - целое. Результатом выражения будет целое число, т.е. максимально 32767. Что мы и видим в журнале. Нужно хотя бы написать ul = b * 1000L;
Компилятор не должен уметь угадывать желания программиста, он должен транслировать то, что написал программист, в машинный код, и не более того.
вообще преобразование типов это одна из самых серьезных предъяв к Си-образным языкам. в общем случае компилятор (точнее транслятор, а еще тончее -стандарт языка) как раз и должен угадывать желания программиста. для этого вообще языки программирования и существуют. а иначе какая проблема- пишите сразу в машиных кодах.
Я бы сказал, что было бы гораздо разумнее, в случае если программист ждет на выходе long, то и все переменные комплиятор бы сначала преобразовывал в long, а уже затем делал расчеты. это же очевидно.
не реализовано это, видимо, совсем по другой причине - это бы потребовало немного больше оперативной памяти при работе программы.
транслятор мог бы анализаровать помещается ли результат в тот тип данных, что задает пользователь, потом выдавать предупреждение о смене типа данных для конкретной переменной и после компилировать как ни в чем не бывало..
Я бы сказал, что было бы гораздо разумнее, в случае если программист ждет на выходе long, то и все переменные комплиятор бы сначала преобразовывал в long, а уже затем делал расчеты. это же очевидно.
Это совсем не очевидно.
Программист ждет, чтобы его программа работала правильно и быстро. Очевидно, что на 8-разрядных процессорах int обрабатывается вдвое дольше, чем byte, а long - вдвое дольше, чем int. Поэтому, когда написано int, компилятор и обрабатывает как int, а когда написано long - обрабатывает как long, и было бы странно, еси бы компилятор работал как-то иначе.
Впрочем, на 32-разрядных процессорах промежуточные вычисления производятся в long, даже если данные short int или byte. Но, опять же, для максимизации скорости вычислений.
Но вообще - да, это особенность C/C++. А именно - зависимость результата вычисления от используемого типа процессора. Впрочем, как и размер int. И это специально оговаривается.
транслятор мог бы анализаровать помещается ли результат в тот тип данных, что задает пользователь, потом выдавать предупреждение о смене типа данных для конкретной переменной и после компилировать как ни в чем не бывало..
Это принципиально невозможно.
Анализ, помещается результат в заданный тип или нет, возможет ТОЛЬКО на этапе выполнения (но не компиляции). Соответственно, компилятор никаких предупреждений выдавать не может. Зато при описании любого языка ОБЯЗАТЕЛЬНО декларируются пределы изменения для каждого из типов данных, и в дельнейшем предполагается, что программист их знает и умеет этими знаниями пользоваться.
Что же касается анализа, помещаются ли данные в рамки конкретного типа в процессе выполнения, то как раз это в компиляторах имеется - установите опцию "check range" и программа в процессе выполнения будет анализировать каждое число. Другое дело, сколько это займет памяти и сколько потребует времени на выполнение.
Так что все в руках программиста: хотите проверку - пожалуйста (со всеми выитекающими), отказались от проверки - не жалуйтесь на раезультат.
Вот недавно видел подобную ошибку у ребят, которые HelfByte Basic компьютер делали. В одной из версий целочисленного Бейсика для своего изделия они явно указали, что возведение в степень глючит. 2^2=3 - так, что, говорят, до особого распоряжения, при возведении в степень добавляйте 1 к результату. При беглом просмотре листинга выяснилось, что выполняется нецелочисленная операция, а от результата просто отсекается дробная часть. В исходнике было сделано округление (к результату добавлено 0.5 и приведено к int) и все заработало.
Ну да...
Прибавлять 1 _после_ или 0.5 _до_. :)
Но вообще - да, это особенность C/C++. А именно - зависимость результата вычисления от используемого типа процессора. Впрочем, как и размер int. И это специально оговаривается.
я может не совсем точно выразился. речь даже не столько об ошибках как у топикстартера (хотя они очень распространены) и не о том как быстрее скомпилировать. речь о том, что ситуация, когда программер предпочел бы, чтобы его промежуточные переменные сразу переводились к типу результирующей переменной более вероятна, чем обратная. т.е. можно было просто сделать по умолчанию приведение типов, а если нужно оставить - то указать это явно. возможно я чего-то не понимаю....
Прибавлять 1 _после_ или 0.5 _до_. :)
совсем не то же самое ))
прибавлять 0.5 ДО - гарантирует правильное округление в любом случае.
а прибавлять единицу после, даст неверный результат при чуть бОльших значениях чем 2*2 ))
транслятор мог бы анализаровать помещается ли результат в тот тип данных, что задает пользователь, потом выдавать предупреждение о смене типа данных для конкретной переменной и после компилировать как ни в чем не бывало..
Не мог бы. В частных случаях, да, а в общем случае это невозможно в принципе.
Да, если бы и мог, эти предупреждения были бы практически на каждую строчку и так задолбали бы, что их бы все выключали. Например:
int a;
......что-то делается...........
int b = a +10;
всё, приплыли - ловите предупреждение - откуда компилятору знать чему будет в данный момент равно a и, стало быть, поместится ли результат в int?
ситуация, когда программер предпочел бы, чтобы его промежуточные переменные сразу переводились к типу результирующей переменной более вероятна, чем обратная. т.е. можно было просто сделать по умолчанию приведение типов, а если нужно оставить - то указать это явно. возможно я чего-то не понимаю....
Вы так думаете?
long a = 110000;
long b = 100000;
int c = a-b;
На каком этапе мы будем приводить к int?
Понимаете, Maverik, конкретных ситуаций - миллионы и в одних случаях одно, в других другое.
Приведу еще один пример:
int a = 30000;
int b = 21;
int c = 100;
int d = a*b/c;
Очевидно, хотя как все члены, так и результат помещается в int, промежуточные вычисления лучше бы проводить в long.
Поэтому в языке существуют вполне логичные правила преобразования типов в процессе вычисления, а если Вам нужно что-то экзотическое (хотя такого экзотического на самом деле - десятки процентов), то следует явно указывать типы.
PS. Что самое смешное, если использовать "родную" для процессора разрядность, то второй пример на Ассемблере будет вычислен именно так, как надо, т.е. с увеличением разрядности для промежуточного результата.
прибавлять 0.5 ДО - гарантирует правильное округление в любом случае.
Ну, не в любом, конечно! Тоже, как и любой инструмент, надо с умом пользовать.
Экспериментировал я тоже как-то с округлением до целого и могу сказать, что прибавление 0.5 не всегда приводило к желаемому результату.
Не помню точно на каком числе, но происходило следующее:
22.4 + 0.5 округлялось как положено к 22, а вот 22.5 + 0.5 округлилось тоже к 22, а ведь по ожиданиям должно было получиться 23. Все остальные числа "с половинками" из исследуемого диапазона округлялись правильно.
Видимо, где-то в недрах получилось что-то типа 22.999999...
Поэтому, если надо округлить, например, число с одним знаком после запятой к целому, я добавляю не 0.5, а 0.51 и все получается, как и ожидается.
Поэтому, если надо округлить, например, число с одним знаком после запятой к целому, я добавляю не 0.5, а 0.51 и все получается, как и ожидается.
Не всё. Как насчёт 0,49? Да и откуда Вам знать сколько там знаков?
А что за проблема с 0,5? Какая разница куда его округлять (если Вы, конечно, не банковсую систему пишете, там то понятно куда)?
На сколько я понимаю, это особенности long и float арифметики. Вот уж не знаю, почему, но в МК-61, например, 2*2=4, а вот 2^2=3.9999(9). Естественно, если отбросить дробную часть - будет 3
В каждой реализации языка есть правила приведения типов. ВОт там то собака и зарыта в большинстве случаев подобных проблем.
Не всё. Как насчёт 0,49? Да и откуда Вам знать сколько там знаков?
В моем случае я просто в цикле к переменной приращивал 0.1, выводил значение в сериал, прибавлял к нему 0.5, переводил в целое и тоже выводил в сериал, а потом просто визуально сравнивал с ожидаемым.
В моем случае я просто в цикле к переменной приращивал 0.1, выводил значение в сериал, прибавлял к нему 0.5, переводил в целое и тоже выводил в сериал, а потом просто визуально сравнивал с ожидаемым.
И что Вы таким образом установили/пытались_установить?
И что Вы таким образом установили/пытались_установить?
Пытался установить, почему в другом скетче при округлении в некоторых случаях я получал не совсем то, что ожидал. Поэтому и сделал такой проверочный скетч.
Боюсь, что выводы, основанные на этой проверке, справедливы исключительно для Вашего скетча, и ни для чего другого.
Хорошо, когда люди даже не догадываются, что способов округления штук 6.
Боюсь, что выводы, основанные на этой проверке, справедливы исключительно для Вашего скетча, и ни для чего другого.
А я и не претендую ни на что. В теме затронули вопрос, что 2х2 не всегда 4. Я подкинул "5 копеек" из своей практики. Кто-то прочитает и пойдет дальше, кто-то возможно и сам с таким столкнется и вспомнит, а кого-то это зацепит и он начнет троллить своим "ну и что?" ;)
А какой шестой?
https://ru.m.wikipedia.org/wiki/Округление
"штук 6" означает "около 6", потому ответ на вопрос в ссылке выше.
Классная ссылка - цитату из Гаусса раньше не знал - блеск! Книгу Уоррена знал, конечно, но от этого она хуже не становится :)
Таки да, я тоже не видел раньше этой фразы, действительно в тему :)