challenge LL Golf Hole 7 - バイト数を読みやすくする

与えられたバイト数を読みやすくしてください。読みやすくとは、いわゆる human readable な表記とします(詳しくはサンプルのコードを参考にしてください)。

与えるバイト数についてはリテラルで与える、標準入力で与える、引数で与えるなどは自由とします。

余力のあるものはこのプログラムを短くしてください。

※ LL Future実行委員の高野光弘です。この出題は LL Future公式の出題であり、優れたものについてはLL Golfのセッションでご紹介させていただくかもしれません。ご理解の上、ご投稿ください。また、LL Futureのチケットは現在も発売中です。よろしければ、メインイベントの方にもぜひご参加ください。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
b = gets.to_i
if b < 10**3
    puts b
elsif b < 10**6
    puts "%.1fk" % (b.to_f/10**3)
elsif b < 10**9
    puts "%.1fM" % (b.to_f/10**6)
elsif b < 10**12
    puts "%.1fG" % (b.to_f/10**9)
else
    puts "%.1fT" % (b.to_f/10**12)
end

Posted feedbacks - C

とりあえず、縮めてないです。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#include <stdio.h>

#define QWORD unsigned long long
#define DWORD unsigned long
#define WORD  unsigned short
#define BYTE  char

int put_unit(char * p,int n,char u){
    if(n) return sprintf(p,"%d%c",n,u);
    if(u=='B') return sprintf(p,"B");
    return 0;
}

void conv_byte(char *p,QWORD num){
    int i;
    if(num==0) sprintf(p++,"0");
    for(i=6;i>=0;i--)
        p+=put_unit(p,(num>>(10*i))&0x3ff,"BKMGTPE"[i]);
}

void conv_put(char *buf,QWORD n){
    conv_byte(buf,n);
    printf("%Ld=%s\n",n,buf);    
}
int main(){
    char buf[64];
    
    conv_put(buf,0);
    conv_put(buf,(BYTE)-1);
    conv_put(buf,(WORD)-1);
    conv_put(buf,(DWORD)-1);
    conv_put(buf,(QWORD)-1);
    
    return 0;
}

一人だけ問題を読み違えているようですが・・・このまま行きます。
本体は155Byte
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
#include <stdio.h>
#include <string.h>

#define QWORD unsigned long long
#define DWORD unsigned long
#define WORD  unsigned short
#define BYTE  char

void conv_byte(char *p,QWORD n){
    int m,i=7;strcpy(p,"0B");
    if(n)while(i--)p+=(m=(n>>10*i)&1023)?sprintf(p,"%d%c",m,"BKMGTPE"[i]):i?0:sprintf(p,"B");
}

void conv_put(char *buf,QWORD n){
    conv_byte(buf,n);
    printf("%Ld=%s\n",n,buf);    
}

int main(){
    char buf[64];
    
    conv_put(buf,(QWORD)-1);
    conv_put(buf,(DWORD)-1);
    conv_put(buf,(WORD)-1);
    conv_put(buf,(BYTE)-1);
    conv_put(buf,0);

    conv_put(buf,(QWORD)1024*1024*1024*1024*1024*1024);
    conv_put(buf,(QWORD)1024*1024*1024*1024*1024);
    conv_put(buf,(QWORD)1024*1024*1024*1024);
    conv_put(buf,(QWORD)1024*1024*1024);
    conv_put(buf,(QWORD)1024*1024);
    conv_put(buf,(QWORD)1024);
    conv_put(buf,(QWORD)1);

    return 0;
}

余分なゼロを出さないように、つまり、 % ./a.out 1073741824 1G と、してみました。サンプルコードだと1G0M0K0Bになります。 再起を使っています。 64bit longlongしか考えないので、 ”E" までの単位にしか対応していません。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include <stdio.h>
#include <stdlib.h>

void bytes(unsigned long long l, char *suf, int zs)
{
        unsigned u l & 0x3FF;
        if(l>1023)
                bytes(l>>10, suf+1,1);
        if(u>0|| !zs && l==0) 
       printf("%d%c",u,*suf)
}

int
main(int argc , char *argv[])
{
        int i;
        unsigned long long l;
        for(i=1;i<argc;i++) {
                l=strtoll(argv[i],NULL,10);
                bytes(l, "BKMGTPE",0);
                putchar('\n');
        }
}

もう少し縮めた。

sprintf版は2文字関数名が増えてるけどタブ・改行含めて145byte、
printf版は同じく126byte・・・かな?
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
#include <stdio.h>
#include <string.h>

#define QWORD unsigned long long
#define DWORD unsigned long
#define WORD  unsigned short
#define BYTE  char

void s_conv_byte(char *p,QWORD n){
    int m,i=7;
    while(i--)p+=(m=(n>>10*i)&1023)|!i&!n?sprintf(p,"%d%c",m,"BKMGTPE"[i]):i?0:sprintf(p,"B");
}


void conv_byte(QWORD n){
    int m,i=7;
    while(i--)(m=(n>>10*i)&1023)|!i&!n?printf("%d%c",m,"BKMGTPE"[i]):i?0:printf("B");
}

void s_conv_put(char *buf,QWORD n){
    s_conv_byte(buf,n);
    printf("%Ld=%s\n",n,buf);    
}

void conv_put(char *buf,QWORD n){
    printf("%Ld=",n,buf);    
    conv_byte(n);
    printf("\n");
}

int main(){
    char buf[64];
    
    conv_put(buf,(QWORD)-1);
    conv_put(buf,(DWORD)-1);
    conv_put(buf,(WORD)-1);
    conv_put(buf,(BYTE)-1);
    conv_put(buf,0);

    conv_put(buf,(QWORD)1024*1024*1024*1024*1024*1024);
    conv_put(buf,(QWORD)1024*1024*1024*1024*1024);
    conv_put(buf,(QWORD)1024*1024*1024*1024);
    conv_put(buf,(QWORD)1024*1024*1024);
    conv_put(buf,(QWORD)1024*1024);
    conv_put(buf,(QWORD)1024);
    conv_put(buf,(QWORD)1);

    return 0;
}

まいど、raynstardです。
単位を文字列として出力してしまえば100バイトまでは減らせそうなのだけど
その先にある壁が越えられないorz

// gcc doukaku202.c

ちなみに、コードをそのまま短くすると↓の通り(104B)
main(){char*t="\0kMGTPE";double d;scanf("%1lf",&d);for(;d>1023;t++){d/=1024;}printf("%.1lf%.1sB\n",d,t);}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
int main(int argc, char *argv[])
{
    char*t="\0kMGTPE??";
    double d;
    scanf("%1lf",&d);
    for(;d>1023;t++)
    {
        d/=1024;
    }
    printf("%.1lf%.1sB\n",d,t);
    return 0;
}

少し改造しました。
同様に縮めると101byteですね
main(){int i=0;double d;for(scanf("%lf",&d);d>1023;i++)d/=1024;printf("%.1lf%cB\n",d,"\0kMGTPE"[i]);}
1
2
3
4
5
6
7
8
int main()
{
    int i=0;
    double d;
    for(scanf("%lf",&d);d>1023;i++)d/=1024;
    printf("%.1lf%cB\n",d,"\0kMGTPE??"[i]);
    return 0;
}

よく見たら、1023Bまでの間が挙動変わっちゃいますね。

出題文から行くとこれでもいいのかな?
main(){int i=0;double d;for(scanf("%lf",&d);d>1023;i++)d/=1024;printf("%.1lf%c\n",d," kMGTPEZY"[i]);}
2BYTE減ったけど、Zetta,Yotta追加した分同じく101Byte
1
2
3
4
5
6
7
8
int main()
{
    int i=0;
    double d;
    for(scanf("%lf",&d);d>1023;i++)d/=1024;
    printf("%.1lf%c\n",d," kMGTPEZY"[i]);
    return 0;
}

うわっ。完全に問題を読み違えていた。恥ずかしい。 だけでは何なので一応プログラムもつけます。全然短くないけど、こっちだとお題に沿ってるかな。 サンプルプログラムは1024ではなくて10**3で割ってるようなのでそうしてみました。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
#include <stdio.h>
#include <stdlib.h>

int
main(int argc , char *argv[])
{
        char * p="BKMGTPE";
        long long l;
        int r=0;
        l=strtoll(argv[1],NULL,10);
        for(;l>1000; r=l%1000, l/=1000, p++);
        printf("%ld.%02d%c\n",(int)l, r/10, *p);
}

どうも仕様として微妙なんですが、1k未満のときは小数点は書かないのがいいんですよね。
あと、1024基準ではなく1000基準ですかね。

ってことで新しく作ってみました。133Byteかな?
1
2
3
4
5
6
main(){
    char*t="\0kMGTPEZY",b[99],*p=gets(b);
    for(while(*++p);p-b>3;p-=3)t++;
    *p=*t?p[2]=*p,*p++=0,'.':0;
    printf("%s%.2s%.1s\n",b,p,t);
}

よく考えてみたらどうせ1024でわってしまう上に小数第一位までしか表示しないので
倍精度で値を保持する必要ありませんでしたね。
指数にしてしまうので単精度で十分と思われ。

祝☆99B

多少お題と違うみたいですけど、とりあえず満足です(ぁ

ちなみに、内部が指数表記なので
30桁とかとんでもない桁数でも動きますが
もちろんオーババッファフローします^^;

main(){char*t="\0kMGTPE";float d;for(scanf("%f",&d);d>1023;t++)d/=1024;printf("%.1f%.1sB\n",d,t);}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
#include <stdio.h>
int main(int argc, char *argc[])
{
        char*t="\0kMGTPE";
        float d;
        for(scanf("%f",&d);d>1023;t++)
        {
                d/=1024;
        }
        printf("%.1f%.1sB\n",d,t);
        return 0;
}

後続の#7358 では問題無くなっていますが
僕のロジックでは%cを利用してはいけません。
%cはバイナリ出力に使いので出力結果をバイナリで確認してみるとわかります。

echo '100' ./a.out | od -x

あとちなみに、こう。氏のロジックだと
iをデータセグメントに持って行ってデフォルトの型に期待しちゃうことで僕よりも短くなります。
といっても98Bなので似たようなものですけど。
文字列と扱うためのキャストが;;
# たぶん、C99です。
1
i;main(){float d;for(scanf("%f",&d);d>1023;i++)d/=1024;printf("%.1f%.1sB\n",d,&("\0kMGTPE"[i]));}

一応、floatにすればというのは気づいてたんですが、さすがに連投しすぎかなと(^^;

100B切ったことですし、ガードも入れましょうか。
これで1024Y以上の場合でも動作します。

ぎりぎり99Byteですね。

ちなみに#7396のは
i;main(){float d;for(scanf("%f",&d);d>1023;i++)d/=1024;printf("%.1f%.1sB\n",d,"\0kMGTPE"+i);}
の93byteでよいはずです^^;
1
i;main(){float d;i=8;for(scanf("%f",&d);i&&d>1023;i--)d/=1024;printf("%.1f%c\n",d,"YZEPTGMk "[i]);}

Index

Feed

Other

Link

Pathtraq

loading...