LINUX.ORG.RU
ФорумTalks

В чём разница между ++i и i++?

 


0

1

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

Перемещено Shaman007 из development

https://imgur.com/a/DjNwdgE

Короч i++ это 3 действия:

  1. Запоминаем старое значение

  2. Делаем +1 и запоминаем новое значение

  3. Возвращаем старое значение

А ++i это 2 действия:

  1. Делаем +1 и запоминаем новое значение

  2. Возвращаем значение

Короч по идее ++i работает чуть быстрее чем i++, хотя эти обе операции и являются атомарными.

 и в нормальных языках разницы между ++i и i++ нет, что уменьшает степень костыльности.

Не говори такой ерунды на собесе, а то услышишь «мы вам перезвоним»

romanlinux ★★★
()
Последнее исправление: romanlinux (всего исправлений: 3)

С таким тупняком только в толксы, а лучше удалить.

anonymous
()

Переменная инкрементируется в любом случае. Оличается возравращаемое значение, в одном случае значение после инкрементации, в другом до инкрементации.

erfea ★★★★★
()

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

Shaman007 ★★★★★
()
Ответ на: комментарий от romanlinux

Разве сегодня компиляторы не переоптимизируют это все эффективнее, в любом случае? А так, не припомню чтобы в реальном коде это как-то улучило читабельность.

maggotroot
()

Что-то сильно жирно.

Meyer ★★★★★
()
Ответ на: комментарий от maggotroot

Вроде как оптимизируют, но лучше всегда знать «наверняка», что и как работает

romanlinux ★★★
()
Ответ на: комментарий от romanlinux

Я ошибся. ВАЖНАЯ ПОПРАВКА!

Операция инкремент и операция декремент НЕ являются атомарными.

romanlinux ★★★
()

И почему существуют оба, а не один? В смысле, зачем в 2021 нужен i++?

Потому, что в борьбе между C и паскалем выиграл C. Из C по соображениям совместимости никто убирать i++ не будет. Другие языки копируют примерно по тем же причинам: сделать несложно, а программистам удобно.

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

К тому же, ++i выглядит красивее

А для меня i++ выглядит красивее. В Java никогда не видел, чтобы цикл писали с ++i, все пишут с i++.

и в нормальных языках разницы между ++i и i++ нет

Это что за языки такие?

Legioner ★★★★★
()
Ответ на: комментарий от maggotroot

С перегрузкой операций - не факт, хотя шансы большие. А если речь об обычных int-ах, то, конечно, всё соптимизируют.

Legioner ★★★★★
()
Последнее исправление: Legioner (всего исправлений: 1)
Ответ на: комментарий от romanlinux

Не говори такой ерунды на собесе, а то услышишь «мы вам перезвоним»

Но если он не скажет такое на собеседовании, то он может оказаться в одной команде с тобой. Будьте осторожнее в своих желаниях ©

gremlin_the_red ★★★★★
()

разницы между ++i и i++ нет

Вот по этому ракеты и падают.

Знаю, что пациент троллит, но всё же:

⍺ := 10
⍵ := ++⍺

⍺ → 11
⍵ → 11

vs.

⍺ := 10
⍵ := ⍺++

⍺ → 11
⍵ → 10

И это таки очень полезно.

beastie ★★★★★
()
Последнее исправление: beastie (всего исправлений: 2)
Ответ на: комментарий от romanlinux

Ух ты, не знал. Всё так.

function test() {
    let a = 1, b = 1;
    const time = performance.now()
    for (let i = 0; i < 10000000; i++);
    console.log('i++', performance.now() - time)
}
function test2() {
    let a = 1, b = 1;
    const time = performance.now()
    for (let i = 0; i < 10000000; ++i);
    console.log('++i', performance.now() - time)
}
test()
test2()

результат:

test()
test2()
VM552:5 i++ 18.299999982118607
VM552:11 ++i 7.4000000059604645
undefined
test()
test2()
VM552:5 i++ 23.599999994039536
VM552:11 ++i 14.299999982118607
undefined
test()
test2()
VM552:5 i++ 9.099999994039536
VM552:11 ++i 5.800000011920929
undefined
test()
test2()
VM552:5 i++ 11.799999982118607
VM552:11 ++i 5.399999976158142
undefined
test()
test2()
VM552:5 i++ 13.400000005960464
VM552:11 ++i 6.4000000059604645
undefined
test()
test2()
VM552:5 i++ 19.200000017881393
VM552:11 ++i 5

Прирост производительности есть для большого количества итераций. Для малого - нет.

1000:

test()
test2()
VM36:5 i++ 0.09999999403953552
VM36:11 ++i 0.09999999403953552
undefined
test()
test2()
VM36:5 i++ 0
VM36:11 ++i 0

10 000, наблюдаю аномалию:

test()
test2()
VM79:5 i++ 0.4000000059604645
VM79:11 ++i 0.6000000238418579
undefined
test()
test2()
VM79:5 i++ 2.100000023841858
VM79:11 ++i 0.19999998807907104
undefined
test()
test2()
VM79:5 i++ 0.5
VM79:11 ++i 0.5
undefined
test()
test2()
VM79:5 i++ 0.29999998211860657
VM79:11 ++i 0.5
undefined
test()
test2()
VM79:5 i++ 0.5
VM79:11 ++i 0.10000002384185791

100 000, аномалия всё ещё есть:

test()
test2()
VM137:5 i++ 4.4000000059604645
VM137:11 ++i 4
undefined
test()
test2()
VM137:5 i++ 0.699999988079071
VM137:11 ++i 4.699999988079071
undefined
test()
test2()
VM137:5 i++ 1
VM137:11 ++i 0.19999998807907104

1 000 000, аномалия есть:

test()
test2()
VM185:5 i++ 7
VM185:11 ++i 4.699999988079071
undefined
test()
test2()
VM185:5 i++ 6.199999988079071
VM185:11 ++i 8.5
undefined
test()
test2()
VM185:5 i++ 1.800000011920929
VM185:11 ++i 2.4000000059604645
undefined
test()
test2()
VM185:5 i++ 2.100000023841858
VM185:11 ++i 1.5999999940395355

И только от 10млн i++ становится однозначно медленней:

test()
test2()
VM240:5 i++ 21.600000023841858
VM240:11 ++i 10
undefined
test()
test2()
VM240:5 i++ 14
VM240:11 ++i 8.400000005960464
undefined
test()
test2()
VM240:5 i++ 17.5
VM240:11 ++i 7.9000000059604645
undefined
test()
test2()
VM240:5 i++ 16.5
VM240:11 ++i 4.300000011920929

JIT не дремлет и выбор решения зависит от условий задачи. Интересно провести эксперимент с другими ЯП, но мне лень, сделайте кто-нибудь за меня. Как там в Java, например?

InterVi ★★★★★
()
Ответ на: комментарий от Shaman007

Как видно по треду, не троллинг и разница действительно есть. Но вот конкретики не хватает - хотелось бы знать, какие языки «нормальные».

InterVi ★★★★★
()
Ответ на: комментарий от Legioner

В Java никогда не видел, чтобы цикл писали с ++i, все пишут с i++.

Запишись к окулисту

Lordwind ★★★★★
()

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

theurs ★★
()
Ответ на: комментарий от theurs

В других языках так делать нельзя

В перле можно, в яве можно и т.д. Так что «В некоторых других языках так делать нельзя».

gremlin_the_red ★★★★★
()
Ответ на: комментарий от Legioner

Никакой борьбы Си с Паскалем не было. Паскаль - это язык, который известен в СССР и больше нигде в мире о нём никогда не слышали.

lenin386 ★★★★
()
Последнее исправление: lenin386 (всего исправлений: 2)
Ответ на: комментарий от lenin386

Паскаль - это язык, который известен в СССР и больше нигде в мире о нём никогда не слышали.

Угумс, именно поэтому чисто американский Classic Mac OS был написан именно на нём. Как и первые версии GCC.

EXL ★★★★★
()
Ответ на: комментарий от tyamur

Ну чудаков везде хватает. А я везде пишу i++ кроме тех случаев, когда по семантике нужен ++i (да и в тех случаях подумаю дважды).

Legioner ★★★★★
()
Ответ на: комментарий от Legioner

Ну мне кажется ++i логичнее. Оператор сразу возвращает результат своего действия. А i++ использовать когда нужно иначе.

tyamur ★★
()
Ответ на: комментарий от InterVi

Хм, на пыхе результаты интересней.

https://sandbox.onlinephpfunctions.com/code/1cedec4adce2a6ce03463f83e0a51220f087a1da

На версии 7.4.13 (просто последняя 7.4) выигрывает ++и, но на версии 8 разница сводится к погрешности (а иногда и++ выигрывает).

fernandos ★★★
()
Ответ на: комментарий от tyamur

Речь о том, когда не надо возвращать результат своего действия. То бишь код вида for (int i = 0; i < str.length(); i++).

Вот grep по исходникам JDK:

$ find -name '*.java' | xargs grep '\w++' | wc -l
20213
$ find -name '*.java' | xargs grep '++\w' | wc -l
2621

Т.е. в принципе оба варианта имеют право на существование, но первый вариант популярней в 7 раз. Поэтому моё имхо, надо предпочитать его, исходя из принципа меньшего удивления.

Legioner ★★★★★
()
Последнее исправление: Legioner (всего исправлений: 3)
Ответ на: комментарий от fernandos

Затестил джаву:

public class Main {
    public static void test() {
        long time = System.nanoTime();
        for (int i = 0; i < 1000000000; i++);
        System.out.println("i++ " + String.valueOf(System.nanoTime() - time));
    }

    public static void test2() {
        long time = System.nanoTime();
        for (int i = 0; i < 1000000000; ++i);
        System.out.println("++i " + String.valueOf(System.nanoTime() - time));
    }

    public static void main(String[] args) {
        //for (int i = 0; i < 10; i++) Main.test();
        for (int i = 0; i < 10; i++) Main.test2();
    }
}

i++ быстрее на старте, ++i быстрее после JIT:

[alex@hard java]$ java Test.java
i++ 4067508
i++ 29474921
i++ 143944
i++ 143664
i++ 130046
i++ 86813
i++ 95892
i++ 90514
i++ 94636
i++ 113353
[alex@hard java]$ java Test.java
i++ 3145249
i++ 7670708
i++ 83111
i++ 79200
i++ 88699
i++ 79130
i++ 84788
i++ 75568
i++ 74660
i++ 86953
[alex@hard java]$ java Test.java
i++ 3642102
i++ 28233416
i++ 70540
i++ 68445
i++ 67676
i++ 65022
i++ 64883
i++ 67537
i++ 82413
i++ 63696

[alex@hard java]$ java Test.java
++i 6875351
++i 44606952
++i 75988
++i 62718
++i 63905
++i 69912
++i 75290
++i 72496
++i 74032
++i 74172
[alex@hard java]$ java Test.java
++i 5049202
++i 6004147
++i 72985
++i 64324
++i 65791
++i 64883
++i 64324
++i 62019
++i 66140
++i 74312
[alex@hard java]$ java Test.java
++i 9412000
++i 1397
++i 15749989
++i 20603
++i 20603
++i 21232
++i 21930
++i 21931
++i 21930
++i 22349

И на всякий случай считал новое время в переменную после цикла, чтобы преобразование и конкатация не влияли. Результат примерно тот же:

[alex@hard java]$ java Test.java
i++ 4541611
i++ 7834555
i++ 65719
i++ 61529
i++ 66906
i++ 69840
i++ 67745
i++ 69560
i++ 64881
i++ 65789
[alex@hard java]$ java Test.java
i++ 8016495
i++ 12321073
i++ 69630
i++ 65859
i++ 66558
i++ 61040
i++ 62157
i++ 65371
i++ 67535
i++ 63345

[alex@hard java]$ java Test.java
++i 5719419
++i 11528512
++i 80177
++i 75148
++i 70608
++i 88627
++i 67675
++i 67675
++i 65370
++i 65790
[alex@hard java]$ java Test.java
++i 10049368
++i 6999659
++i 81922
++i 76964
++i 75707
++i 73332
++i 81503
++i 77313
++i 76126
++i 76824

версия:

[alex@hard java]$ java --version
openjdk 11.0.11 2021-04-20
OpenJDK Runtime Environment (build 11.0.11+9)
OpenJDK 64-Bit Server VM (build 11.0.11+9, mixed mode)
InterVi ★★★★★
()
Последнее исправление: InterVi (всего исправлений: 3)
Ответ на: комментарий от LikeABoss

Куда уж мне до эталонного топлива типа тебя, мечты любого реактора. Вот только ни на что кроме топлива не годишься.

Как такое школоло на лорчик-то забрело, а?

WitcherGeralt ★★
()
Ответ на: комментарий от WitcherGeralt

Как такое школоло на лорчик-то забрело, а?

Ещё в 2011, ЕВОЧЯ

LikeABoss
() автор топика
Ответ на: комментарий от LikeABoss

О вкусах не спорят.

Так говорят люди с отсутствием вкуса

Так отвечают люди, желающие посраться о вкусах. :) При этом неспособные уловить дипломатически-тонкий намёк на то, что срач уже начался. :)

dimgel ★★★★★
()

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

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

ergo ★★★
()
Последнее исправление: ergo (всего исправлений: 1)
Ответ на: комментарий от lenin386

Паскаль - это язык, который известен в СССР и больше нигде в мире о нём никогда не слышали

И поэтому Windows изначально писали на Паскале, ага.

no-such-file ★★★★★
()
Ответ на: комментарий от lenin386

Паскаль - это язык, который известен в СССР и больше нигде в мире о нём никогда не слышали.

Подобной толщины наброс более подобает анонимному троллю, чем уважаемому автору полезной программы

hobbit ★★★★★
()
Ответ на: комментарий от no-such-file

Windows изначально писали на Паскале

Windows писали на ассемблере.

После ассемблера перешли на С, потом на С++. Может где-то и был паскаль…

В С и ассемблере можно указывать calling conventions. Брали паскалевскую, потому что это экономило немного байт.

https://devblogs.microsoft.com/oldnewthing/20040102-00/?p=41213

Pascal does not support functions with a variable number of parameters, so it can use the callee-clean convention. Parameters are pushed from left to right, because, well, it seemed the natural thing to do. Function name decoration consists of conversion to uppercase. This is necessary because Pascal is not a case-sensitive language.

Nearly all Win16 functions are exported as Pascal calling convention. The callee-clean convention saves three bytes at each call point, with a fixed overhead of two bytes per function. So if a function is called ten times, you save 3*10 = 30 bytes for the call points, and pay 2 bytes in the function itself, for a net savings of 28 bytes. It was also fractionally faster. On Win16, saving a few hundred bytes and a few cycles was a big deal. 
fsb4000 ★★★★★
()
Последнее исправление: fsb4000 (всего исправлений: 1)
Ответ на: комментарий от hateyoufeel

Нормальные пацаны пишут i-=-1

А пацаны повышенной чоткости пишут

(def a (atom 0))
(swap! a inc)

и не разбрасывают mutable state по всему мясокомбинату.

Nervous ★★★★★
()
Последнее исправление: Nervous (всего исправлений: 1)
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.