reprobado que promedio programa para obtener numeros grupo con calificaciones calcule calcular arreglos aprobado alumnos c++ math unsigned-integer

para - programa que calcule el promedio de 5 calificaciones en c++



¿Cómo puedo promediar de forma segura dos entradas sin firmar en C++? (11)

El último acercamiento

unsigned int average = (a / 2) + (b / 2); // Equals: 2147486147 as expected

no funciona a veces debido a errores de redondeo.

Utilizando solo las matemáticas enteras, me gustaría promediar "con seguridad" dos entradas sin signo en C ++.

Lo que quiero decir con "seguridad" es evitar desbordamientos (y cualquier otra cosa que se pueda pensar).

Por ejemplo, promediar 200 y 5000 es fácil:

unsigned int a = 200; unsigned int b = 5000; unsigned int average = (a + b) / 2; // Equals: 2600 as intended

Pero en el caso de 4294967295 y 5000, entonces:

unsigned int a = 4294967295; unsigned int b = 5000; unsigned int average = (a + b) / 2; // Equals: 2499 instead of 2147486147

Lo mejor que he encontrado es:

unsigned int a = 4294967295; unsigned int b = 5000; unsigned int average = (a / 2) + (b / 2); // Equals: 2147486147 as expected

¿Hay mejores formas?


Lo que tienes está bien, con el detalle menor de que afirmará que el promedio de 3 y 3 es 2. Supongo que no quieres eso; Afortunadamente, hay una solución fácil:

unsigned int average = a/2 + b/2 + (a & b & 1);

Esto simplemente golpea la copia de seguridad promedio en el caso de que ambas divisiones se truncaran.


Si el código es para un micro incrustado, y si la velocidad es crítica, el lenguaje ensamblador puede ser útil. En muchos microcontroladores, el resultado del agregado iría naturalmente a la bandera de acarreo, y existen instrucciones para cambiarlo a un registro. En un ARM, la operación promedio (fuente y destino en los registros) podría hacerse en dos instrucciones; cualquier equivalente en lenguaje C probablemente rinda al menos 5, y probablemente un poco más que eso.

Por cierto, en máquinas con tamaños de palabra más cortos, las diferencias pueden ser aún más importantes. En una serie PIC-18 de 8 bits, promediar dos números de 32 bits tomaría doce instrucciones. Hacer los turnos, agregar y corregir tomaría 5 instrucciones para cada turno, ocho para el complemento y ocho para la corrección, por lo que 26 (no es una diferencia de 2,5 veces, pero probablemente sea más significativa en términos absolutos).


Si no te molesta un pequeño ensamblado en línea x86 (sintaxis C de GNU), puedes aprovechar la sugerencia de supercat para usar rotate-with-carry después de agregar para poner los 32 bits altos del resultado completo de 33 bits en un registro .

Por supuesto, generalmente debería importar usar inline-asm, porque derrota algunas optimizaciones ( https://gcc.gnu.org/wiki/DontUseInlineAsm ). Pero aquí vamos de todos modos:

// works for 64-bit long as well on x86-64, and doesn''t depend on calling convention unsigned average(unsigned x, unsigned y) { unsigned result; asm("add %[x], %[res]/n/t" "rcr %[res]" : [res] "=r" (result) // output : [y] "%0"(y), // input: in the same reg as results output. Commutative with next operand [x] "rme"(x) // input: reg, mem, or immediate : // no clobbers. ("cc" is implicit on x86) ); return result; }

El modificador % para decirle al compilador que los argumentos son conmutativos realmente no ayuda a hacer un mejor asm en el caso que intenté, llamando a la función con y una constante o un puntero-deref (operando de memoria). Probablemente usar una restricción coincidente para un operando de salida lo anule, ya que no puede usarlo con operandos de lectura-escritura.

Como puede ver en el explorador del compilador Godbolt , este compila correctamente, y también lo hace una versión donde cambiamos los operandos a unsigned long , con el mismo asm en línea. clang3.9 hace un lío, y decide usar la opción "m" para la restricción "rme" , por lo que almacena en la memoria y utiliza un operando de memoria.

RCR-by-one no es demasiado lento, pero sigue siendo de 3 uops en Skylake, con una latencia de 2 ciclos. Es genial en las CPU AMD, donde RCR tiene latencia de ciclo único. (Fuente: tablas de instrucciones de Agner Fog , consulte también la wiki de la etiqueta x86 para ver los enlaces de rendimiento x86). Todavía es mejor que la versión de @ sellibitze, pero peor que la versión dependiente de orden de @ Sheldon. (Ver código en Godbolt)

Pero recuerde que el aster en línea derrota optimizaciones como la propagación constante, por lo que cualquier versión pura de C ++ será mejor en ese caso.


Su método no es correcto si ambos números son impares, ej. 5 y 7, el promedio es 6 pero su método # 3 devuelve 5.

Prueba esto:

average = (a>>1) + (b>>1) + (a & b & 1)

con operadores matemáticos solamente:

average = a/2 + b/2 + (a%2) * (b%2)


Tu último acercamiento parece prometedor. Puede mejorar eso considerando manualmente los bits más bajos de ayb:

unsigned int average = (a / 2) + (b / 2) + (a & b & 1);

Esto proporciona los resultados correctos en caso de que tanto a como b sean impares.


Use un int sin signo de 64 bits como el marcador de posición para la suma, vuelva a lanzar a int después de dividir por 2. Cuestionable si esto es "mejor", pero sin duda evita el problema de desbordamiento con un mínimo esfuerzo.


Y la respuesta correcta es ...

(A&B)+((A^B)>>1)



int[] array = { 1, 2, 3, 4, 5, 6, 7, 8, 9 }; decimal avg = 0; for (int i = 0; i < array.Length; i++){ avg = (array[i] - avg) / (i+1) + avg; }

espera avg == 5.0 para esta prueba