HDU_4239_Decoding EDSAC Data(模拟)

Decoding EDSAC Data
Time Limit:3000MS     Memory Limit:0KB     64bit IO Format:%lld & %llu

Description

Download as PDF

The world's first full-scale, stored-program, electronic, digital computer was the EDSAC (Electronic Delay Storage AutomaticCalculator). The EDSAC had an accumulator-based instruction set, operating on 17-bit words (and 35-bit double words), and used a 5-bit teletypewriter code for input and output.

The EDSAC was programmed using a very simple assembly language: a single letter opcode followed by an unsigned decimal address, followed by the the letter `F' (for full word) or `D' (for double word). For example, the instruction ``A 128 F" would mean ``add the full word at location 128 to the accumulator", and would be assembled into the 17-bit binary value, 11100000100000000, consisting of a 5-bit opcode (11100 = ``add"), an 11-bit operand (00010000000 = 128), and a single `0' bit denoting a full word operation (a 1 bit would indicate a double word operation).

Although arithmetic on the EDSAC was fixed point two's complement binary, it was not mere integer arithmetic (as is common with modern machines). The EDSAC hardware assumed a binary point between the leftmost bit and its immediate successor. Thus the hardware could handle only values in the range -1.0$ \le$x < 1.0. For example:

ValueBinary Representation
-1.010000000000000000
1/201000000000000000
3/401100000000000000
-1/211000000000000000

As you can see, the largest possible positive value was:

01111111111111111 = 0.9999847412109375

and the smallest possible positive value was:

00000000000000001 = 2 -16 = 0.0000152587890625

(This also happens to be the increment between successive values on the EDSAC).

By a curious coincidence (or an elegant design decision), the opcode for the add operation (11100) was the same as the teleprinter code for the letter `A'. The opcode for subtract was the same as the teleprinter code for `S' (01100), and so on. This simplified the programming for the assembler (which, incidentally, was a mere 31 instructions long). The EDSAC teleprinter alphabet was ``PQWERTYUIOJ#SZK*?F@D!HNM&LXGABCV" (with `P' = 00000, `Q' = 00001, and so on, up to 'V' = 11111).

Unfortunately, the EDSAC assembler had no special directives for data values. On the other hand, there was no reason that ordinary instructions couldn't be used for this, thus, an EDSAC programmer desiring to reserve space for the constant 3/4 (represented as 01100000000000000) would use the instruction `S 0 F' and for 1/3 (which is approximately represented as 00101010101010101) `T 682 D', and so on.

Your job is to write a program that will translate EDSAC instructions into the appropriate decimal fractions.

Input

The first line of input contains a single integer P, ( 1$ \le$P$ \le$1000), which is the number of data sets that follow. Each data set is a single line that contains N (the dataset number), followed by a space, followed by an EDSAC instruction of the form: ` c $ \sqcup$ d $ \sqcup$ s', where c is a single character in the EDSAC alphabet, d is an unsigned decimal number ( 0$ \le$d < 211), and s is either a `D' or `F'.


Note: $ \sqcup$ represents a single space.

Output

For each data set there is one line of output. It contains the data set number (N) followed by a single space, followed by the exact decimal fraction represented by the by the EDSAC instruction, including a minus sign (for negative values). The format for the decimal fraction is:sb.ddd..., where s is an optional minus sign, b is either a `1' or `0', and d is any decimal digit (0-9). There must be at least 1 and at most 16 digits after the decimal point. Trailing zeros in the fraction must be suppressed.

Sample Input

13
1 P 0 F
2 I 0 F
3 & 0 F
4 ? 0 F
5 Q 1228 D
6 P 0 D
7 V 2047 D
8 * 2047 D
9 ? 0 D
10 P 256 F
11 V 1536 F
12 T 682 D
13 T 54 F

Sample Output

1 0.0
2 0.5
3 -0.5
4 -1.0
5 0.0999908447265625
6 0.0000152587890625
7 -0.0000152587890625
8 0.9999847412109375
9 -0.9999847412109375
10 0.0078125
11 -0.015625
12 0.3333282470703125
13 0.31414794921875

题型:模拟


题意:与hdu4238的输入输出相反,将用符号表示的二进制数转变为十进制。


分析:

        首先将输入那些符号根据题意变为二进制,共有17位,其中第一位为符号位,用于判断正负,其余的按照二进制求十进制小数部分的方法来求就行了。


代码:

#include<stdio.h>
#include<string.h>
char map[33] = {'P' , 'Q' , 'W' , 'E' , 'R' , 'T' , 'Y' , 'U' , 'I' , 'O' , 'J' , '#' , 'S' , 'Z' , 'K' , '*' , '?' , 'F' , '@' , 'D' , '!' , 'H' , 'N' , 'M' , '&' , 'L' , 'X' , 'G' , 'A','B','C','V'};
char a[3] , b[3];
int n , num;
double ans;
char tans[10000];
char str[30];


void f(char t){
    int d = 4;
    for(int i = 0 ; i < 32 ; i ++){
        if(t == map[i]){
            while(i != 0){
                str[d --] = i % 2 + '0';
                i /= 2;
            }
            break;
        }
    }
    while(d >= 0){
        str[d --] = '0';
    }
    return ;
}

void ff(int t){

    int d = 15;

    while(t != 0){
        str[d --] = t % 2 + '0';
        t /= 2;
    }
    while(d >= 5){
        str[d --] = '0';
    }

    return ;
}

void fff(char t){
    if(t == 'F') str[16] = '0';
    if(t == 'D') str[16] = '1';
}


int main(){

    scanf("%d" , &n);

        for(int i = 1 ; i <= n ; i ++){
            ans = 0;
            double c = 0.5;
            scanf("%*d%s%d%s" , a , &num , b);
            f(a[0]);
            //
            ff(num);

            fff(b[0]);
            str[17] = '\0';
            //printf("%s\n" , str);
            printf("%d " , i);
            if(str[0] == '0'){
                for(int i = 1 ; i < 17 ; i ++){
                    ans += (str[i] - '0') * c;
                    c /= 2;
                }
                sprintf(tans , "%.16lf" , ans);
            }
            else{
                for(int i = 1 ; i < 17 ; i ++){
                    ans += (str[i] - '0') * c;
                    c /= 2;
                    //printf("ans = %lf\n" , ans);
                }
                ans += -1.0;
                sprintf(tans , "%.16lf" , ans);
            }

            if(ans == 0.0){
                printf("0.0\n");
            }
            else if(ans == -1.0){
                printf("-1.0\n");
            }
            else{
                int di;
                for(di = strlen(tans) - 1 ; di >= 0 ; di --){
                    if(tans[di] != '0') break;
                }
                tans[di + 1] = '\0';
                    //printf("di = %d\n" , di);
                printf("%s" , tans);
                printf("\n");
            }

            /*if(str[0] == '0') sprintf(tans , "%.16lf" , ans);
            else sprintf(tans , "%.16lf" , -(1 - ans));
            //for(int i = )
            printf("%d " , i);
            if(ans != 0){
                int di;
                for(di = strlen(tans) - 1 ; di >= 0 ; di --){
                    if(tans[di] != '0') break;
                }
                tans[di + 1] = '\0';
                //printf("di = %d\n" , di);
                printf("%s" , tans);
                printf("\n");
            }
            else if (ans == 0 && str[0] == '1'){
                printf("-1.0\n");
            }
            else{
                printf("0.0\n");
            }*/
        }



    return 0;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
好的,关于 HDU4992 求所有原根的问题,我可以给出以下解答: 1. 首先,我们需要知道什么是原根。原根是指模 n 意义下,所有与 n 互质的数 a 的最小正整数 k 次幂对 n 取模的值覆盖了所有与 n 互质的数。简单来说,就是如果一个数 a 是模 n 意义下的原根,那么 a 的任何正整数次幂对 n 取模的值都不相同,且能覆盖所有与 n 互质的数。 2. 为了求模 n 意义下的所有原根,我们需要先求出与 n 互质的数的个数 phi(n)。phi(n) 可以使用欧拉函数求出。 3. 然后,我们需要枚举模 n 意义下的所有数,判断它是否是原根。具体来说,对于每个 a,我们需要判断 a 的每个小于 phi(n) 的正整数次幂对 n 取模的值是否都不相同,且能覆盖所有与 n 互质的数。如果是,那么 a 就是模 n 意义下的原根。 4. 代码实现可以参考以下 Java 代码: ``` import java.util.*; public class Main { static int gcd(int a, int b) { return b == 0 ? a : gcd(b, a % b); } static int phi(int n) { int res = n; for (int i = 2; i * i <= n; i++) { if (n % i == 0) { res = res / i * (i - 1); while (n % i == 0) { n /= i; } } } if (n > 1) { res = res / n * (n - 1); } return res; } static int pow(int a, int b, int mod) { int res = 1; while (b > 0) { if ((b & 1) != 0) { res = res * a % mod; } a = a * a % mod; b >>= 1; } return res; } static boolean check(int a, int n, int phi) { for (int i = 1, j = pow(a, i, n); i <= phi; i++, j = j * a % n) { if (j == 1) { return false; } } return true; } public static void main(String[] args) { Scanner scanner = new Scanner(System.in); while (scanner.hasNext()) { int n = scanner.nextInt(); int phi = phi(n); List<Integer> ans = new ArrayList<>(); for (int i = 1; i < n; i++) { if (gcd(i, n) == 1 && check(i, n, phi)) { ans.add(i); } } Collections.sort(ans); for (int x : ans) { System.out.print(x + " "); } System.out.println(); } } } ``` 其中,gcd 函数用于求最大公约数,phi 函数用于求欧拉函数,pow 函数用于快速幂求模,check 函数用于判断一个数是否是原根。在主函数中,我们依次读入每个 n,求出 phi(n),然后枚举模 n 意义下的所有数,判断它是否是原根,将所有原根存入一个 List 中,最后排序输出即可。 希望我的回答能够帮到你,如果你有任何问题,欢迎随时提出。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值