Использование переменных цикла после цикла
От: Khimik  
Дата: 14.09.23 07:33
Оценка:
Мне надо перевести фрагмент кода с C++ на Delphi. В частности эту функцию:

static int sizeofints( const int num_of_ints, unsigned int sizes[]) {
    int i, num;
    unsigned int num_of_bytes, num_of_bits, bytes[32], bytecnt, tmp;
    num_of_bytes = 1;
    bytes[0] = 1;
    num_of_bits = 0;
    for (i=0; i < num_of_ints; i++) {    
    tmp = 0;
    for (bytecnt = 0; bytecnt < num_of_bytes; bytecnt++) {
        tmp = bytes[bytecnt] * sizes[i] + tmp;
        bytes[bytecnt] = tmp & 0xff;
        tmp >>= 8;
    }
    while (tmp != 0) {
        bytes[bytecnt++] = tmp & 0xff;
        tmp >>= 8;
    }
    num_of_bytes = bytecnt;
    }
    num = 1;
    num_of_bytes--;
    while (bytes[num_of_bytes] >= num) {
    num_of_bits++;
    num *= 2;
    }
    return num_of_bits + num_of_bytes * 8;

}


Тут какое-то вычисление, сколько бит понадобится на хранение нескольких чисел указанного максимального размера. И меня смутило, что переменная bytecnt, которая вначале служит счётчиком цикла, используется также после цикла. Это нормально в C++?
"Ты должен сделать добро из зла, потому что его больше не из чего сделать". АБ Стругацкие.
Re: Использование переменных цикла после цикла
От: T4r4sB Россия  
Дата: 14.09.23 07:51
Оценка:
Здравствуйте, Khimik, Вы писали:

K>Мне надо перевести фрагмент кода с C++ на Delphi. В частности эту функцию:




K>Тут какое-то вычисление, сколько бит понадобится на хранение нескольких чисел указанного максимального размера. И меня смутило, что переменная bytecnt, которая вначале служит счётчиком цикла, используется также после цикла. Это нормально в C++?


Да. Используй цикл while, потому что for в С++ и Дельфи не всегда невзаимозаемы.
Одно в другое можно перевести только в простом случает когда переменная цикла объявляется прямо в заголовке цикла, имеет соавнение с числом в качестве верхнего условия и инкремент/декремент на единичку в качестве перехода
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
Re: Использование переменных цикла после цикла
От: velkin Удмуртия https://kisa.biz
Дата: 14.09.23 07:58
Оценка:
Здравствуйте, Khimik, Вы писали:

K>И меня смутило, что переменная bytecnt, которая вначале служит счётчиком цикла, используется также после цикла. Это нормально в C++?


Можешь вместо такого.
    for (bytecnt = 0; bytecnt < num_of_bytes; bytecnt++) {

Написать вот так.
    for (int bytecnt = 0; bytecnt < num_of_bytes; bytecnt++) {

И даже вот так.
    for (int bytecnt = 0; bytecnt < num_of_bytes; ++bytecnt) {

Вот такой стиль,
    int i, num;
    unsigned int num_of_bytes, num_of_bits, bytes[32], bytecnt, tmp;

когда предварительно объявляешь локальные переменные, да ещё и скопом, пришёл из древности. Вспоминается какой-нибудь Pascal.

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

А если захочешь изменить стиль как я выше написал, то придётся ниже переписать алгоритм, потому что bytecnt не будет в той области видимости.
Re[2]: Использование переменных цикла после цикла
От: Khimik  
Дата: 14.09.23 08:54
Оценка:
Здравствуйте, T4r4sB, Вы писали:

TB>Да. Используй цикл while, потому что for в С++ и Дельфи не всегда невзаимозаемы.

TB>Одно в другое можно перевести только в простом случает когда переменная цикла объявляется прямо в заголовке цикла, имеет соавнение с числом в качестве верхнего условия и инкремент/декремент на единичку в качестве перехода

Ок, вот этот перевод корректный?

function cbsizeofints(num_of_ints: Integer; sizes: array of int64): Integer;
var
  i, num: Integer;
  num_of_bytes, num_of_bits, bytecnt, tmp: int64;
  bytes: array[0..31] of int64;
begin
  num_of_bytes := 1;
  bytes[0] := 1;
  num_of_bits := 0;

  for i := 0 to num_of_ints - 1 do
  begin
    tmp := 0;
    bytecnt:=0;
    while bytecnt<num_of_bytes - 1 do
    begin
      tmp := bytes[bytecnt] * sizes[i] + tmp;
      bytes[bytecnt] := tmp and $ff;
      tmp := tmp shr 8;
      inc(bytecnt);
    end;

    while tmp <> 0 do
    begin
      bytes[bytecnt] := tmp and $ff;
      tmp := tmp shr 8;
      Inc(bytecnt);
    end;

    num_of_bytes := bytecnt;
  end;

  num := 1;
  Dec(num_of_bytes);

  while bytes[num_of_bytes] >= num do
  begin
    Inc(num_of_bits);
    num := num * 2;
  end;

  Result := num_of_bits + num_of_bytes * 8;
end;


Тут мне не совсем понятно, если превращать for в while, инкремент надо ставить в начале теле цикла, или в конце.
"Ты должен сделать добро из зла, потому что его больше не из чего сделать". АБ Стругацкие.
Отредактировано 14.09.2023 8:55 Khimik . Предыдущая версия .
Re[3]: Использование переменных цикла после цикла
От: T4r4sB Россия  
Дата: 14.09.23 09:14
Оценка:
Здравствуйте, Khimik, Вы писали:

K>Ок, вот этот перевод


Unsigned тебе ни о чем не говорит? Даже банально на русский переведи хотя бв

K>Тут мне не совсем понятно, если превращать for в while, инкремент надо ставить в начале теле цикла, или в конце.


В конце
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
Re: Использование переменных цикла после цикла
От: Pavel Dvorkin Россия  
Дата: 14.09.23 09:21
Оценка: +2
Здравствуйте, Khimik, Вы писали:

K>Тут какое-то вычисление, сколько бит понадобится на хранение нескольких чисел указанного максимального размера. И меня смутило, что переменная bytecnt, которая вначале служит счётчиком цикла, используется также после цикла. Это нормально в C++?


Да. Она описана не в for, а выше, поэтому может использоваться до выхода на свою }
With best regards
Pavel Dvorkin
Re[4]: Использование переменных цикла после цикла
От: Khimik  
Дата: 14.09.23 09:37
Оценка:
Здравствуйте, T4r4sB, Вы писали:

K>>Ок, вот этот перевод


TB>Unsigned тебе ни о чем не говорит? Даже банально на русский переведи хотя бв


Ну я перевёл unsigned int как int64, формально на Delphi надо как Cardinal (32-битный интегер без знака). Это же не принципиально, int64 для всего годится.
"Ты должен сделать добро из зла, потому что его больше не из чего сделать". АБ Стругацкие.
Re: Использование переменных цикла после цикла
От: DiPaolo Россия  
Дата: 14.09.23 10:28
Оценка:
K>
K>static int sizeofints( const int num_of_ints, unsigned int sizes[]) {
K>    int i, num;
K>    unsigned int num_of_bytes, num_of_bits, bytes[32], bytecnt, tmp;
K>    num_of_bytes = 1;
K>    bytes[0] = 1;
K>    num_of_bits = 0;
K>    for (i=0; i < num_of_ints; i++) {    
K>    tmp = 0;
K>    for (bytecnt = 0; bytecnt < num_of_bytes; bytecnt++) {
K>        tmp = bytes[bytecnt] * sizes[i] + tmp;
K>        bytes[bytecnt] = tmp & 0xff;
K>        tmp >>= 8;
K>    }
K>    while (tmp != 0) {
K>        bytes[bytecnt++] = tmp & 0xff;
K>        tmp >>= 8;
K>    }
K>    num_of_bytes = bytecnt;
K>    }
K>    num = 1;
K>    num_of_bytes--;
K>    while (bytes[num_of_bytes] >= num) {
K>    num_of_bits++;
K>    num *= 2;
K>    }
K>    return num_of_bits + num_of_bytes * 8;

K>}
K>


K>Это нормально в C++?


Нет. Код больше поход на Си. Более того, похоже на какую-то числодробилку (условную в данном случае) с заточкой на минимальное использование памяти и перформанс. Такой код обычно редко правится и упор идет не на читабельность. Вот там такое принято, да

PS Хотя пустые строки никто не запрещает вставлять для визуального разделения на блоки
Патриот здравого смысла
Re[3]: Использование переменных цикла после цикла
От: velkin Удмуртия https://kisa.biz
Дата: 14.09.23 12:04
Оценка: 2 (1)
Здравствуйте, Khimik, Вы писали:

K>Тут мне не совсем понятно, если превращать for в while, инкремент надо ставить в начале теле цикла, или в конце.


В конце.
    int num_of_bytes = 2, bytecnt = 0;
    while (bytecnt < num_of_bytes)
    {
        // код в цикле
        bytecnt++;
    }

    int num_of_bytes = 2;
    for (int bytecnt = 0; bytecnt < num_of_bytes; bytecnt++)
    {
        // код в цикле
    }

1. Если объявляешь и определяешь переменные в инициализации цикла for, то они будут видны только внутри области видимости цикла.
2. Цикл for в C++ это не такая примитивная штука, как в Pascal. Можно сделать несколько инициализаций через запятую. Можно так же добавить несколько выражений конца цикла опять же через запятую. Можно создать счётчик цикла, а можно какое-нибудь другое вычисление.

Для примера первая попавшаяся ссылка.
for (инициализация; предусловие; петля)

1. Инициализация выполняется один раз можно сказать, что вне петли цикла, только область видимости будет действовать только на петлю.
2. Предусловие выполняется каждый раз в начале петли. А это считай условие while, то есть for это не просто цикл со счётчиком, а цикл с предусловием в котором можно задать счётчик, а можно задать и не счётчик.
3. Выражение, которое выполняется в конце петли.

Вот это считай одно и тоже.
    int num_of_bytes = 2, bytecnt = 0;
    while(bytecnt < num_of_bytes)
    {
        // код в цикле
        bytecnt++;
    }

Просто меняем на for и оставляем пустую инициализацию и выражение конца петли.
    int num_of_bytes = 2, bytecnt = 0;
    for (;bytecnt < num_of_bytes;)
    {
        // код в цикле
        bytecnt++;
    }
Re[5]: Использование переменных цикла после цикла
От: T4r4sB Россия  
Дата: 14.09.23 13:03
Оценка: +1
Здравствуйте, Khimik, Вы писали:

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


K>>>Ок, вот этот перевод


TB>>Unsigned тебе ни о чем не говорит? Даже банально на русский переведи хотя бв


K>Ну я перевёл unsigned int как int64, формально на Delphi надо как Cardinal (32-битный интегер без знака). Это же не принципиально, int64 для всего годится.


Это принципиально, у знаковых чисел другая реакция на пепеполнения, на сдвиги (?), деление другое.
А еще другой размер может тоде гдето проявиться.
В битовых операциях лучше не пренебрегать этим всем
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
Отредактировано 14.09.2023 13:04 T4r4sB . Предыдущая версия .
Re[6]: Использование переменных цикла после цикла
От: Khimik  
Дата: 14.09.23 13:55
Оценка:
Здравствуйте, T4r4sB, Вы писали:

K>>Ну я перевёл unsigned int как int64, формально на Delphi надо как Cardinal (32-битный интегер без знака). Это же не принципиально, int64 для всего годится.


TB>Это принципиально, у знаковых чисел другая реакция на пепеполнения, на сдвиги (?), деление другое.

TB>А еще другой размер может тоде гдето проявиться.
TB>В битовых операциях лучше не пренебрегать этим всем

По этому вопросу тоже лично я очень не люблю всякие сдвиги, мне не хочется в этом разбираться. Полагаю, почти всегда вместо например сдвига влево лучше просто умножать число в два раза (если только не актуальна скорость). Так понятнее, соответственно меньше будет ошибок.
"Ты должен сделать добро из зла, потому что его больше не из чего сделать". АБ Стругацкие.
Re[7]: Использование переменных цикла после цикла
От: T4r4sB Россия  
Дата: 14.09.23 14:08
Оценка: +2
Здравствуйте, Khimik, Вы писали:

K> По этому вопросу тоже лично я очень не люблю всякие сдвиги, мне не хочется в этом разбираться. Полагаю, почти всегда вместо например сдвига влево лучше просто умножать число в два раза (если только не актуальна скорость). Так понятнее, соответственно меньше будет ошибок.


Дело не в люблю-не-люблю и даже не в скорости , компилятор не тупой и умеет по возможности заменять умножение на сдвиг. Делл в том, какой смысл у опеоации требуется исходя из контекста. Если там важны именно битовые представления то надо писать сдвиг. Если важно числовое значение то надо умножать на 2
У тебя явно битовые манипуляции
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
Re: Использование переменных цикла после цикла
От: Pzz Россия https://github.com/alexpevzner
Дата: 14.09.23 14:25
Оценка:
Здравствуйте, Khimik, Вы писали:

K>Тут какое-то вычисление, сколько бит понадобится на хранение нескольких чисел указанного максимального размера. И меня смутило, что переменная bytecnt, которая вначале служит счётчиком цикла, используется также после цикла. Это нормально в C++?


При чем здесь C++? Последнее значение переменной, достигнутор в цикле, может быть полезным дополнительным результатом алгоритма, реализуемого этим циклом.

Другой вопрос, что именно в этой программе на выходе из цикла bytecnt сделается равным num_of_bytes, после чего его, возможно, еще разок-другой поинкрементят, а результат запихнут в num_of_bytes. Логичнее было бы там, где while (tmp != 0), num_of_bytes и использовать вместо bytecnt. Было бы чуть яснее, и одним присваиванием меньше.
Re[8]: Использование переменных цикла после цикла
От: Khimik  
Дата: 14.09.23 14:53
Оценка:
Здравствуйте, T4r4sB, Вы писали:

TB>Дело не в люблю-не-люблю и даже не в скорости , компилятор не тупой и умеет по возможности заменять умножение на сдвиг. Делл в том, какой смысл у опеоации требуется исходя из контекста. Если там важны именно битовые представления то надо писать сдвиг. Если важно числовое значение то надо умножать на 2

TB>У тебя явно битовые манипуляции

Ну это понятно, в этой программе они используются для сжатия цифровых данных, а я бы ни за что не реализовывал этот алгоритм сжатия через сдвиги, мне намного комфортнее обычное умножение или div.
Кстати обратил внимание, что в C деление одинаково прописывается для целых чисел и флоатов, а нас в Delphi не так, для целочисленного деления есть div, по-моему это правильнее.
"Ты должен сделать добро из зла, потому что его больше не из чего сделать". АБ Стругацкие.
Re[2]: Использование переменных цикла после цикла
От: Alekzander  
Дата: 14.09.23 15:16
Оценка: +1
Здравствуйте, Pavel Dvorkin, Вы писали:

K>>Тут какое-то вычисление, сколько бит понадобится на хранение нескольких чисел указанного максимального размера. И меня смутило, что переменная bytecnt, которая вначале служит счётчиком цикла, используется также после цикла. Это нормально в C++?


PD>Да. Она описана не в for, а выше, поэтому может использоваться до выхода на свою }


До Студии 7.1 скоуп был от начала цикла до конца блока. Соответственно, два одинаковых цикла подрял с i написать было нельзя (второй должен был быть без объявления). Переносить проекты было незабываемое удовольствие.
Re: Использование переменных цикла после цикла
От: kov_serg Россия  
Дата: 14.09.23 15:48
Оценка:
Здравствуйте, Khimik, Вы писали:

K>Мне надо перевести фрагмент кода с C++ на Delphi. В частности эту функцию:


И какие трудности? Примерно так, но предполагается что sizes[i]<>0 и то что результат влазит в 32 байта. т.е. <= 256
function sizeofints(sizes:array of cardinal):integer;
  var j,zn:integer;
  var z:array[32] of byte;
  procedure z_mul(x:cardinal);
  var i:integer; carry:cardinal;
  begin
    i:=0; carry:=0;
    while i<zn or carry<>0 do
      inc(carry,z[i]*x);
      z[i]:=carry; carry:=carry shr 8;
      inc(i);
    end
    zn:=i;
  end
  function bits(x:byte);begin
    result:=0; while x<>0 do begin inc(result); x:=x shr 1; end
  end
begin
    zn:=1; z[0]:=1;
    for j:=0 to length(sizes)-1 do z_mul(sizes[j]);
    result:=(zn-1)*8+bits(z[zn-1]);
end
Отредактировано 14.09.2023 15:52 kov_serg . Предыдущая версия . Еще …
Отредактировано 14.09.2023 15:50 kov_serg . Предыдущая версия .
Отредактировано 14.09.2023 15:49 kov_serg . Предыдущая версия .
Re[9]: Использование переменных цикла после цикла
От: T4r4sB Россия  
Дата: 14.09.23 15:49
Оценка:
K>Ну это понятно, в этой программе они используются для сжатия цифровых данных, а я бы ни за что не реализовывал этот алгоритм сжатия через сдвиги, мне намного комфортнее обычное умножение или div.

Дело не в комфорте а в закладываемом смысле. Тут битовые операции — значит пиши их
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
Re: Использование переменных цикла после цикла
От: Khimik  
Дата: 16.09.23 08:45
Оценка:
Извиняюсь за занудство, но в моём коде на C++ в первом сообщении, когда закончится первый цикл с bytecnt и запустится while (tmp != 0) {, bytecnt будет равен num_of_bytes-1 или num_of_bytes?

Второй вопрос — строчка bytes[bytecnt++] = tmp & 0xff делает логическое умножение tmp на 256, т.е. у tmp оставляется только последний байт?
"Ты должен сделать добро из зла, потому что его больше не из чего сделать". АБ Стругацкие.
Re[2]: Использование переменных цикла после цикла
От: T4r4sB Россия  
Дата: 16.09.23 12:55
Оценка:
Здравствуйте, Khimik, Вы писали:

K>Извиняюсь за занудство, но в моём коде на C++ в первом сообщении, когда закончится первый цикл с bytecnt и запустится while (tmp != 0) {, bytecnt будет равен num_of_bytes-1 или num_of_bytes?


K>Второй вопрос — строчка bytes[bytecnt++] = tmp & 0xff делает логическое умножение tmp на 256, т.е. у tmp оставляется только последний байт?


Погугли C++ playground если не хочешь себе ставить крестокомпилятор.
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
Re[2]: Использование переменных цикла после цикла
От: vsb Казахстан  
Дата: 16.09.23 14:33
Оценка:
Здравствуйте, Khimik, Вы писали:

K>Извиняюсь за занудство, но в моём коде на C++ в первом сообщении, когда закончится первый цикл с bytecnt и запустится while (tmp != 0) {, bytecnt будет равен num_of_bytes-1 или num_of_bytes?


Вот цикл:

    for (bytecnt = 0; bytecnt < num_of_bytes; bytecnt++) {
        tmp = bytes[bytecnt] * sizes[i] + tmp;
        bytes[bytecnt] = tmp & 0xff;
        tmp >>= 8;
    }


Этот цикл можно переписать таким образом:

bytecnt = 0;
while (bytecnt < num_of_bytes) {
  tmp = bytes[bytecnt] * sizes[i] + tmp;
  bytes[bytecnt] = tmp & 0xff;
  tmp >>= 8;

  bytecnt++;
}


таким образом должно быть очевидно, что данный цикл завершится, когда условие (bytecnt < num_of_bytes) станет ложным. Т.е. после цикла bytecnt будет равен num_of_bytes.

K>Второй вопрос — строчка bytes[bytecnt++] = tmp & 0xff делает логическое умножение tmp на 256, т.е. у tmp оставляется только последний байт?


Про логическое умножение на 256 не понял, такая операция мне не знакома. А так — да, верно, только правильно говорить "младший байт", а не "последний", что такое "последний байт" — вопрос совсем не очевидный.

Я попросил ChatGPT перевести код из первого сообщения, ниже напишу его вариант, за корректность не ручаюсь, но может быть будет полезно.

  Скрытый текст
Here is the translated code from C++ to Delphi:

```delphi
function sizeofints(const num_of_ints: Integer; sizes: array of Cardinal): Integer;
var
  i, num: Integer;
  num_of_bytes, num_of_bits, bytecnt, tmp: Cardinal;
  bytes: array[0..31] of Byte;
begin
  num_of_bytes := 1;
  bytes[0] := 1;
  num_of_bits := 0;
  for i := 0 to num_of_ints - 1 do
  begin
    tmp := 0;
    for bytecnt := 0 to num_of_bytes - 1 do
    begin
      tmp := bytes[bytecnt] * sizes[i] + tmp;
      bytes[bytecnt] := tmp and $FF;
      tmp := tmp shr 8;
    end;
    while tmp <> 0 do
    begin
      bytes[bytecnt] := tmp and $FF;
      Inc(bytecnt);
      tmp := tmp shr 8;
    end;
    num_of_bytes := bytecnt;
  end;
  num := 1;
  Dec(num_of_bytes);
  while bytes[num_of_bytes] >= num do
  begin
    Inc(num_of_bits);
    num := num * 2;
  end;
  Result := num_of_bits + num_of_bytes * 8;
end;
```

Explanation:
- I changed the `int` and `unsigned int` types to their Delphi equivalents: `Integer` and `Cardinal`.
- I adjusted the array parameter to be a dynamic array in Delphi.
- C++ arrays are 0-indexed as are Delphi arrays, so we didn't need to change the indexing in the translation.
- The `for` loops and `while` loops were adapted to Delphi's syntax.
- Bitwise operations remain the same, but the shift right operator is `shr` in Delphi instead of `>>`.
- The `return` statement has been changed to assigning the `Result` variable, which is how you return values from functions in Delphi.
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.