напишите функцию на сях (очень простую)

kozicin

посчитать количество ненулевых битов в переменной типа Double

maggi14

может, это и изврат, но я бы:
записал в память дабл
считал бы ее как несколько интов
посчитал бы количество нулей

kozicin

code плиз
думать некогда, гарай тут умирает, надо отнести преподу

Julie16

 #include <stdio.h>

int s( double val )
{
int i, j;
int ret = 0;
union
{
double v;
char c[ sizeof( double ) ];
} a;

a.v = val;

for ( i = 0; i < sizeof( double ); i++ )
{
for ( j = 0; j < 8; j++ )
{
ret += a.c[i] & 1;
a.c[i] >>= 1;
}
}

return ret;
}

int main
{
printf( "%d\n", s( 1.0 ) ) ;
}

maggi14



int nNonZero(unsigned int a)
{
int i = 0;
int c;
for (c = 0; c < sizeof(unsigned int) * 8; c++)
i += (a >> c) % 2;
return i;
}

int foo(double x)
{
int num = 0;
for (int c = 0; c < sizeof(double)/sizeof(unsigned int); c++)
num += nNonZerounsigned int*(&x + c * sizeof(unsigned int;
return num;
}

не проверял, но, надеюсь, сработает. Здесь учтено, что длина дабла нацело делится на длину инта. Можно, в принципе, снять ограничение, если вместо unsigned int писать unsigned char.

Julie16

Неверно. Надо убрать int c из цикла, и + с * sizeof( unsigned int ). Причем указатель &x вначале привести к указателю на char. Или скобки по другому расставить.

maggi14

с ансайнт интом согласен, опечатка. А про инт цэ не понял.

Julie16

C не умеет объявлять таким образом переменную.

ppplva

int f(double d)
{
int cnt = 0;
int i,j;
for (i=0; i<sizeof(double); ++i)
for (j=0; j<8; ++j)
cnt += char*)&d)[i] >> j) & 1;
return cnt;
}

maggi14

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

ppplva

Да, перед char лучше приписать unsigned.

kozicin

гарай уже ушел
можно расслабица

sergey_m


union
{
double v;
char c[ sizeof( double ) ];
} a;

a.v = val;

for ( i = 0; i < sizeof( double ); i++ )
{
for ( j = 0; j < 8; j++ )
{
ret += a.c[i] & 1;
a.c[i] >>= 1;
}
}
Я гоню, или должен быть unsigned char?

sergey_m

Кстати оптимизация:

for ( i = 0; i < sizeof( double ); i++ )
{
while (a.c[i] > 0)
{
ret += a.c[i] % 2;
a.c[i] /= 2;
}
}

По идее на случайном инпуте должна оптимизировать в 1.7 раза.

Flack_bfsp

C не умеет объявлять таким образом переменную.
С-99 умеет.

ppplva

Я гоню, или должен быть unsigned char?
Гонишь.

maggi14

желателен чтобы не думать, как там реализуется % для отрицательных чисел на данной архитектуре

Dasar

быстрее будет так:

while (a.c[i] > 0)
{
bitCount++;
a.c[i] = a.c[i] & (a.c[i]-1);
}

если бить double на инты, а не char-ы, то в среднем будет еще быстрее.
есть еще более быстрый способ - но он уже извратный - его так с ходу не вспомнить.

Vladislav177Rus

Просветите меня, разве это:
a.c[i] /= 2
оптимизация относительно
a.c[i] >>= 1
на IA-32?

okunek

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

ppplva

О % там речи не шло.
Знаковый сдвиг, насколько я знаю, везде реализован подходящим образом.

Dasar

Если будет signed char, то при сдвиге левая единица будет размножаться.
для жесткого for-а с 8 - это не страшно, для остальных более быстрых алгоритмов - это будет проблемой.

Vladislav177Rus

Странно, а почему на разные?
int main{
int a=1024, b=1024;
a /= 2;
b >>= 1;
exit(0);
}
        .file   "main.cpp"
.version "01.01"
gcc2_compiled.:
.text
.p2align 2,0x90
.globl main
.type main,@function
main:
pushl %ebp
movl %esp,%ebp
subl $24,%esp
movl $1024,-4(%ebp)
movl $1024,-8(%ebp)
movl -4(%ebp%eax
cltd
movl %edx,%ecx
shrl $31,%ecx
leal (%ecx,%eax%edx
movl %edx,%eax
sarl $1,%eax
movl %eax,-4(%ebp)
sarl $1,-8(%ebp)
addl $-12,%esp
pushl $0
call exit
addl $16,%esp
xorl %eax,%eax
jmp .L2
.p2align 2,0x90
.L2:
leave
ret
.Lfe1:
.size main,.Lfe1-main
.ident "GCC: (GNU) cplusplus 2.95.4 20020320 [FreeBSD]"

sergey_m

> если бить double на инты, а не char-ы, то в среднем будет еще быстрее.
Я пытался, но не особо получилось. Мне кажется разбивать double на intы означает опираться на конкретную реализацию переменных с плавающей точкой. А union{} предложенный Антоном, плевал на реализацию double.
> есть еще более быстрый способ - но он уже извратный - его так с ходу не вспомнить.
Типа вот этого?

#define g21 0x55555555ul /* = 0101_0101_0101_0101_0101_0101_0101_0101 */
#define g22 0x33333333ul /* = 0011_0011_0011_0011_0011_0011_0011_0011 */
#define g23 0x0f0f0f0ful /* = 0000_1111_0000_1111_0000_1111_0000_1111 */
static __inline u_char
bit_count(uint32_t v)
{
v = (v & g21) + v >> 1) & g21);
v = (v & g22) + v >> 2) & g22);
v = (v + (v >> 4 & g23;
return (v + (v >> 8) + (v >> 16) + (v >> 24 & 0x3f;

По-моему для double не прокатит, потому что фиг знает что он из себя представляет.

a_tischkevich

Мне кажется разбивать double на intы означает опираться на конкретную реализацию переменных с плавающей точкой.
По-моему для double не прокатит, потому что фиг знает что он из себя представляет.
Бля

Dasar

> Я пытался, но не особо получилось. Мне кажется разбивать double на intы означает опираться на конкретную
> реализацию переменных с плавающей точкой. А union{} предложенный Антоном, плевал на реализацию double.
можно сделать что-то такое страшное.

double v;
int * i = (int*)&v;
unsigned short * si = (..)&v;
unsigned byte * bi = (..)&v; //приведения можно и через union сделать - будет быстрее
int len = sizeof(v);
int pos = 0;
while(len - pos >= sizeof(unsigned int
{
bitCount+=CalcBitsInInt(*(i+pos;
pos += 4;
}
while(len - pos >= sizeof(unsigned short
{
bitCount+=CalcBitsInWord(*(si+pos;
pos += 2;
}
while(len - pos >= sizeof(unsigned byte
{
bitCount+=CalcBitsInByte(*(bi+pos;
pos += 1;
}

okunek

насчет сдвига: sar - из-за того, что int юзается.
а деление - хз.

Dasar

> #define g21 0x55555555ul /* = 0101_0101_0101_0101_0101_0101_0101_0101 */
Да, это ОНО.

sergey_m

Узнал много нового. Похоже на большинстве платформ представление одинаково.
Например, gcc пишут, что всё будет по стандарту if hardware is perfect, но всё равно не определяют __STDC_IEC_559__.

sergey_m

Кстати, если ты такой умный, то скажи в каких константах определено сколько бит отдано под мантиссу и под экспоненту?

a_tischkevich

Post deleted by

a_tischkevich

ЗЫ В моём компиляторе это, видимо
DBL_MANT_DIG // float.h

sergey_m

Так вот непонятно оговаривает ли стандарт значение. На IEEE 754, который первая ссылка в гугле, получается как оговаривает. На самом деле на IEEE754 никто не ссылается. C99 ссылается на IEC 60559, который у меня не получается найти. Есть смутные утверждения, что IEEE754 == IEC 60599.

antn

Народ! Всем спасибо! Я сегодня сдал!
(Лучше поздно чем никогда)

rosali

Странно, а почему на разные?

IvladV71

за диплом засел
Оставить комментарий
Имя или ник:
Комментарий: