1

Тема: С Чому відповідь завжди нуль?

u% не працює

#include <stdio.h>
#include <ctype.h>
 
unsigned foo(char* src)
{
    unsigned total = 0;
    for (unsigned idx = 0; *src; src++)
        total += (++idx & 1) & isdigit(*src);
    return total;
}
int main()
{
    char symbols[] = "lkdrjvf9ei48r4hjrfwh74h827h34r0239r34jt93o84rtj";
        printf("Digits on even places found=%u", foo(symbols));
    return 0;
}

2

Re: С Чому відповідь завжди нуль?

Бо isdigit повертає не 1 та 0, а non-zero value. На кшталт 1024 абощо.
І взагалі - не намагайтеся оптимізувати програму, доки не досягнуто працездатності. Усі ці двійкові фокуси чудові, але спершу напишіть без них.

Подякували: P.Y.1

3 Востаннє редагувалося ur_naz (21.04.2021 14:11:46)

Re: С Чому відповідь завжди нуль?

#include <stdbool>
...
(bool)isdigit(*src);

4

Re: С Чому відповідь завжди нуль?

ur_naz написав:
#include <stdbool>
...
(bool)isdigit(*src);

Та не треба ніяких (bool)
Досить лише не пхати & туди, де треба &&, і це працюватиме і в C89, в якому stdbool не було.

Подякували: wander1

5

Re: С Чому відповідь завжди нуль?

&& набагато повільніше за &
до речи, їх і зараз там нема

6

Re: С Чому відповідь завжди нуль?

ur_naz написав:

&& набагато повільніше за &
до речи, їх і зараз там нема

Ну нащо дурню писати? && в деяких випадках значно швидше за &. Бо мінімальне обчислення.

Подякували: 0xDADA11C7, Arete, tchort3

7

Re: С Чому відповідь завжди нуль?

В деяких? тобто в деяких випадках буде краш, а в деяких не буде? чи це не відповідь, чому?

8 Востаннє редагувалося wander (22.04.2021 02:26:08)

Re: С Чому відповідь завжди нуль?

&& - буде ефективніше у всіх випадках, коли виконуватиметься "short-circuit" обчислення, як от в цьому випадку.
& - буде ефективніше в окремих випадках, наприклад, при уникненні умовних гілок (але пам'ятаємо про branch misprediction) або при використанні, як модуля, в тих же бітмасках (хоча зараз компілятори і самі можуть в такі оптимізації).

Одне, це, коли використання && та & дає різний ефект на виконання програми, інше - оптимізації. В даному випадку, проблема саме в тому, що через неправильне використання && та & постраждала працездатність програми, а не швидкодія. Оптимізації такого рівня, це, скажімо так, оптимізації останньої інстанції (в 99,9% випадків проблемним місцем будуть не ці оператори), бо спочатку потрібно провести тести та довести що заміна && на & не зробила ще гірше.

Подякували: leofun011

9 Востаннє редагувалося koala (22.04.2021 06:26:47)

Re: С Чому відповідь завжди нуль?

І знову ж не завжди мінімальне обчислення буде швидшим, бо & - це однотактова операція, а && - кілька операцій. && буде швидшим, коли часто є нулі ліворуч, а праворуч стоїть якась дорога операція (виклик важкої функції, наприклад).
Конкретно тут треба тестувати, як швидше, і я не особливо здивуюся, якщо результати будуть дуже суттєво залежати від компілятора, цільової платформи і налаштувань.

Подякували: tchort, leofun012

10

Re: С Чому відповідь завжди нуль?

Якщо міняти & на &&, то треба мати на увазі, що в одному з її параметрів відбувається побічна дія (інкремент). Поки операція побітова, порядок її параметрів не має значення, а логічна робить обчислення коротким шляхом (тобто, виявивши, що один із параметрів має значення нуль, другий не обчислює). Якщо спершу обчислюється лівий параметр, і інкремент лишається тільки в лівому, це не критично, але якщо їх переставити, виникнуть проблеми з перевіркою парності, яка визначається цим інкрементом.

Потім, а що взагалі повертає операція a && b, якщо a ненульове, b — не нуль і не один? Наскільки я розумію, результатом буде b (а не 1) — яке в даному прикладі потім буде додано до суми, тому вийде якась нісенітниця.

Найпростіше пофіксити приклад, замінивши isdigit(*src) на !!isdigit(*src) (подвійне заперечення) або на isdigit(*src)!=0 (порівняння з нулем) — тоді результатом буде гарантовано або 0, або 1, що початково очікувалось автором теми.

11 Востаннє редагувалося koala (22.04.2021 09:01:51)

Re: С Чому відповідь завжди нуль?

Булеві операції повертають 1 чи 0, залежно від того, чи є аргументи 0.
... && isdigit() - цілком коректно відпрацює.

У сучасних мовах люблять повертати друге значення замість булевого; але це не про C.

Подякували: P.Y., leofun012

12

Re: С Чому відповідь завжди нуль?

Ем, ну, зрозуміло, що мінімальне обчислення матиме перевагу лише при відкиданні важких ф-й, наприклад. В іншому випадку, це взагалі не матиме сенсу.

(foo() && bar()) // очікується, що мінімальне обчислення матиме сенс

bool a = foo();
bool b = bar();
(a && b) // компілятор згенерує
(a &  b) // однаково оптимальний код

Зрозуміло, що це в таких програмах, як от у ТС, можна було б щось таке розглядати, чи в якихсь дійсно окремих випадках, де б заміна && на & (чи навпаки) доведено мала сенс. Якщо ж формулювати загальне правило, то краще використовувати && для логічного AND та & для bitwise AND, і будь-хто, хто читатиме ваш код знайде його простим та зрозумілим.