напишите функцию на сях (очень простую)
записал в память дабл
считал бы ее как несколько интов
посчитал бы количество нулей
думать некогда, гарай тут умирает, надо отнести преподу
#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 ) ) ;
}
не проверял, но, надеюсь, сработает. Здесь учтено, что длина дабла нацело делится на длину инта. Можно, в принципе, снять ограничение, если вместо unsigned int писать unsigned char.
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;
}
Неверно. Надо убрать int c из цикла, и + с * sizeof( unsigned int ). Причем указатель &x вначале привести к указателю на char. Или скобки по другому расставить.
с ансайнт интом согласен, опечатка. А про инт цэ не понял.
C не умеет объявлять таким образом переменную.
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;
}
я знаю. Но, во-первых, подозреваю, что и на пласпласе задачу примут. Во-вторых, мне так писать экономнее, а привести синтаксис к сишному сможет любой.
Да, перед char лучше приписать unsigned.
можно расслабица
Я гоню, или должен быть unsigned char?
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;
}
}
for ( i = 0; i < sizeof( double ); i++ )
{
while (a.c[i] > 0)
{
ret += a.c[i] % 2;
a.c[i] /= 2;
}
}
По идее на случайном инпуте должна оптимизировать в 1.7 раза.
C не умеет объявлять таким образом переменную.С-99 умеет.
Я гоню, или должен быть unsigned char?Гонишь.
желателен чтобы не думать, как там реализуется % для отрицательных чисел на данной архитектуре
если бить double на инты, а не char-ы, то в среднем будет еще быстрее.
while (a.c[i] > 0)
{
bitCount++;
a.c[i] = a.c[i] & (a.c[i]-1);
}
есть еще более быстрый способ - но он уже извратный - его так с ходу не вспомнить.
a.c[i] /= 2оптимизация относительно
a.c[i] >>= 1на IA-32?
имхо каким бы комплиятором не пользовался, он заменит деление на сдвиг
Знаковый сдвиг, насколько я знаю, везде реализован подходящим образом.
для жесткого for-а с 8 - это не страшно, для остальных более быстрых алгоритмов - это будет проблемой.
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]"
Я пытался, но не особо получилось. Мне кажется разбивать 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 не прокатит, потому что фиг знает что он из себя представляет.
Мне кажется разбивать double на intы означает опираться на конкретную реализацию переменных с плавающей точкой.
По-моему для double не прокатит, потому что фиг знает что он из себя представляет.Бля
> реализацию переменных с плавающей точкой. А 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;
}
а деление - хз.
Да, это ОНО.
Например, gcc пишут, что всё будет по стандарту if hardware is perfect, но всё равно не определяют __STDC_IEC_559__.
Кстати, если ты такой умный, то скажи в каких константах определено сколько бит отдано под мантиссу и под экспоненту?
Post deleted by
DBL_MANT_DIG // float.h
Так вот непонятно оговаривает ли стандарт значение. На IEEE 754, который первая ссылка в гугле, получается как оговаривает. На самом деле на IEEE754 никто не ссылается. C99 ссылается на IEC 60559, который у меня не получается найти. Есть смутные утверждения, что IEEE754 == IEC 60599.
(Лучше поздно чем никогда)
Странно, а почему на разные?
за диплом засел
Оставить комментарий
kozicin
посчитать количество ненулевых битов в переменной типа Double