【发布时间】:2018-01-25 16:29:38
【问题描述】:
我有一个算法问题需要加速:)
我需要一个 32 位随机数,精确的 10 位设置为 1。但同时,像 101(12 月 5 日)和 11(12 月 3 日)这样的模式被视为非法。
现在 MCU 是 8051(8 位),我在 Keil uVision 中测试了所有这些。我的第一次尝试完成,给出了解决方案
0x48891249
1001000100010010001001001001001 // correct, 10 bits 1, no 101 or 11
问题是它在 97 秒或 1165570706 个 CPU 周期内完成,这太荒谬了!!!
这是我的代码
// returns 1 if number is not good. ie. contains at leats one 101 bit sequence
bool checkFive(unsigned long num)
{
unsigned char tmp;
do {
tmp = (unsigned char)num;
if(
(tmp & 7) == 5
|| (tmp & 3) == 3
) // illegal pattern 11 or 101
return true; // found
num >>= 1;
}while(num);
return false;
}
void main(void) {
unsigned long v,num; // count the number of bits set in v
unsigned long c; // c accumulates the total bits set in v
do {
num = (unsigned long)rand() << 16 | rand();
v = num;
// count all 1 bits, Kernigen style
for (c = 0; v; c++)
v &= v - 1; // clear the least significant bit set
}while(c != 10 || checkFive(num));
while(1);
}
一个聪明的头脑的大问题:) 可以做得更快吗?看来我的做法很幼稚。
提前谢谢你,
哇,我印象深刻,谢谢大家的建议。但是,在接受之前,这些天我需要对其进行测试。
现在使用第一个选项(查找)它只是不现实,将完全炸毁整个 8051 微控制器的 4K RAM :) 如下图所示,我测试了代码块中的所有组合,但有远远超过 300,直到 5000 索引才完成......
我用来测试的代码
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <stdbool.h>
//#define bool bit
//#define true 1
//#define false 0
// returns 1 if number is not good. ie. contains at leats one 101 bit sequence
bool checkFive(uint32_t num)
{
uint8_t tmp;
do {
tmp = (unsigned char)num;
if(
(tmp & 7) == 5
|| (tmp & 3) == 3
) // illegal pattern 11 or 101
return true; // found
num >>= 1;
}while(num);
return false;
}
void main(void) {
uint32_t v,num; // count the number of bits set in v
uint32_t c, count=0; // c accumulates the total bits set in v
//printf("Program started \n");
num = 0;
printf("Program started \n");
for(num=0; num <= 0xFFFFFFFF; num++)
{
//do {
//num = (uint32_t)rand() << 16 | rand();
v = num;
// count all 1 bits, Kernigen style
for (c = 0; v; c++)
v &= v - 1; // clear the least significant bit set
//}while(c != 10 || checkFive(num));
if(c != 10 || checkFive(num))
continue;
count++;
printf("%d: %04X\n", count, num);
}
printf("Complete \n");
while(1);
}
也许我可以重新提出问题:
我需要一个号码:
- 精确(已知)数量的 1 位,在我的示例中为 10
- 没有 11 或 101 个模式
- 剩余的零可以是任意的
所以不知何故,只洗牌里面的 1 位。
或者,取一个 0x00000000 并在随机位置添加 1 位中的 10 个,但非法模式除外。
【问题讨论】:
-
CLOCKS_PER_SEC 宏不可靠(它已过时)。在现代计算机上,97 秒最多接近 3000 亿次循环
-
只是 randomly shuffle 一个由 10 个 1 和 22 个 0 组成的数组。
-
@EugeneSh。但是要排除的模式呢?
-
我想知道这样的数字到底有多少。很容易彻底检查。我预计不会那么多,所以也许只是枚举它们并随机选择?
-
这个算法是颠倒的。由于规则非常严格,因此最好使用规则生成而不是生成 int 并查看其是否正常