LL Golf Hole 7 - バイト数を読みやすくする
Posted feedbacks - Nested
Flatten Hidden一応YiBまで対応(処理系が対応してればだけど. 変換対象のバイト数はスタイルシートパラメタnで与えます。 449bytes, 実質443bytes
1 2 3 4 5 6 7 8 | <transform version="2.0" xmlns="http://www.w3.org/1999/XSL/Transform" xmlns:y="y">
<output method="text"/><param name="n"/>
<variable name="u" select="('B','KiB','MiB','GiB','TiB','PiB','EiB','ZiB','YiB')"/>
<template match="/"><value-of select="y:f($n,1)"/></template>
<function name="y:f"><param name="m"/><param name="i"/>
<sequence select="if($m<1024)then($m,$u[$i])else
y:f(round-half-to-even($m div 1024,2),$i+1)"/>
</function></transform>
|
#7312と同じ考えでC++で。入力は標準入力。 133bytes。実質132bytes
1 2 3 | #include <iostream>
char*p=" \bKiMiGiTiPiEiZiYi";
main(){double n;std::cin>>n;for(;1024<n;p+=2)n/=1024;std::cout<<n<<*p<<p[1]<<"B";}
|
標準入力から読み込み。 Yまで対応しています。
1 2 3 4 5 6 7 8 9 10 11 | using System;
class P {
static void Main() {
double n = double.Parse(Console.ReadLine());
string s = " kMGTPEZY";
int c = 0, l = 1000;
for (; n >= l; c++)
n /= l;
Console.WriteLine("{0:f1}{1}", n, s[c]);
}
}
|
CPANモジュールNumber::Bytes::Humanを使ってone-liner。入力は標準入力 perl -MNumber::Bytes::Human=format_bytes -nlE'say format_bytes$_’ 66bytesかな
see: Number::Bytes::Human
-p を使ってもう1byte削れた. おまけでv5.10じゃなくても大丈夫に perl -MNumber::Bytes::Human=format_bytes -ple'$_=format_bytes$_’
とりあえず、縮めてないです。
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;
}
|
もう少し縮めた。 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;
}
|
Squeak Smalltalk で。
1 2 3 4 5 6 7 | | byte |
byte := 123456789012345.
^(#('' k M G T P E Z) inject: byte into: [:result :unit |
result < 1024 ifTrue: [^result asString, unit].
result / 1024 roundTo: 0.1]) asString, 'Y'
"=> '112.3T' "
|
お題のSample Codeを参考に書いてみました。byte数は標準入力から与えます。111byte。
1 2 | $i=int(((($n=<>)=~tr/0-9/0-9/)-1)/3);
printf(($i?"%.1f":"%d")."%s\n",$n/10**($i*3),('',qw(k M G T P E Z Y))[$i])
|
1000で割る方で書いてみました。 タブと改行を除いて 166B
1 2 3 4 5 6 7 8 | class P{
public static void main(String[]a){
double d=Double.parseDouble(a[0]);
int i=0,l=1000;
for(;d>=l;d/=l,i++);
System.out.printf("%.1f%s",d," kMGTPEZY".charAt(i));
}
}
|
投稿直後に縮むことに気付いたので再投稿。 これで 164B
1 2 3 4 5 6 7 8 | class P{
public static void main(String[]a){
double d=Double.parseDouble(a[0]);
int i=0,l=1000;
for(;d>=l;d/=l,i++);
System.out.printf("%.1f"+" kMGTPEZY".charAt(i),d);
}
}
|
#7320をお手本にJavaScriptで。( toFixed()メソッドがちょっと嫌な感じですが。)
1 2 3 4 | (function (d) {
for (var i = 0; d >= 1024; d /= 1024, i++);
alert(d.toFixed(2) + ' kMGTPEZY'.charAt(i));
})(123456789012345);
|
あんまり納得のいく出来ではない。forの中が汚い。
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 | def readable(byte, base=1024):
'''
>>> readable(0)
'0'
>>> readable(100)
'100'
>>> readable(1024)
'1.0k'
>>> readable(1900*1024)
'1.9M'
>>> readable(1900*1024*1024)
'1.9G'
>>> readable(1900*(1024**7))
'1.9Y'
'''
for c in ['','k', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y']:
d, m = divmod(byte, base)
if not d:
if c:
return '%.1f%s'%(float(exp)/base, c)
else:
return str(m)
else:
exp = byte
byte = d
return 'Not supported'
if __name__ == '__main__':
import doctest
doctest.testmod()
|
大差でこちらだと思う。 **を一杯計算するが・・・。
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 | def readable(byte, base=1024):
'''
>>> readable(0)
'0'
>>> readable(100)
'100'
>>> readable(1024)
'1.0k'
>>> readable(1900*1024)
'1.9M'
>>> readable(19000*1024)
'18.6M'
>>> readable(190000*1024)
'185.5M'
>>> readable(1900*1024*1024)
'1.9G'
>>> readable(1900*(1024**7))
'1.9Y'
'''
for i, c in enumerate(['','k', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y']):
if byte < base **(i+1):
if c:
return '%.1f%s'%(float(byte)/base**i, c)
else:
return str(byte)
return 'Not supported'
if __name__ == '__main__':
import doctest
doctest.testmod()
|
前出の再帰バージョン。 再帰のありがたみはあまりない。 しいて言えば、Yでかけないやつが来たときもreadableではないが数字列を返す点か。
1 2 3 4 5 6 7 8 9 10 | def readable(byte, base=1024):
def sub(byte, k, bound, unit):
if byte < bound:
if unit and unit[0]:
return '%.1f%s'%(float(byte)/k, unit[0])
else:
return str(byte)
else:
return sub(byte, k*base, bound *base, unit[1:])
return sub(byte, 1, base, ['', 'k', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y'])
|
移植しました。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | #load "nums.cma";;
open Num
let conv =
let base = (Int 1024) in
let rec sub byte k bound = function
| [] -> raise (Invalid_argument "over")
| hd::tl ->
if byte </ bound then
Printf.sprintf "%.1f%s" (float_of_num (byte // k)) hd
else
sub byte (k */ base) (bound */ base) tl
in
fun byte -> sub byte (Int 1) base ["b"; "k"; "M"; "G";"T"]
;;
(*
conv (Int 1024);;
conv (Big_int (Big_int.big_int_of_string "10000000000"));;
*)
|
R的にはループを使わない方向で。
1 2 3 4 5 6 | bytes.pretty <- function(n){
u <- c('', 'k', 'M', 'G', 'T')
r <- 1024^(1:length(u)-1)
i <- which.min(abs(512-n/r))
sprintf("%.1f%s", n/r[i], u[i])
}
|
1024 でなくて 1000 でいいんですね?
1000だと文字の長さや正規表現を使った解が作りやすいけど、「バイト数」というお題を考えると1024でなければ意味がないし・・・。
この違いは結構大きいのではないかと思います。
LL Golf の Lingrチャットによると 1024 でも 1000 でもお好きな方でとのことらしいです。
データは標準入力から。 サンプルプログラムのように k=1000 で。 >echo 123|jconsole unit1.ijs 123 >echo 1234|jconsole unit1.ijs 1.2k >echo 123456789|jconsole unit1.ijs 123.5M >echo 12345678901234567|jconsole unit1.ijs 12345.7T
1 | exit wd;(a<1e3){a;~(0j1":a%10^3*b),(b=.((a=.x:".}:1!:1[3)>10^3*i.5)i:1){' kMGT'
|
raw_input()を使って書いてみた。86bytes。
1 | s=raw_input();p=-min(4,(len(s)-1)/3)*3;print[s,s[:p]+'.'+s[p:1+p]+'kMGT'[-1-p/3]][p<0]
|
4bytes削った。82bytes
1 | s=raw_input();p=-min(4,(len(s)-1)/3)*3;print[s,s[:p]+'.'+s[p]+'kMGT'[-1-p/3]][p<0]
|
ワンライナーPythonの限界に挑戦中。91bytes (本体 80bytes).
1 | python -c"s=raw_input();p=min(12,len(s)-1)/3*-3;print[s,s[:p]+'.'+s[p]+' kMGT'[-p/3]][p<0]"
|
またクラス作るパターンでやりました。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | #!/usr/bin/env gosh
(define-class <b> ()
((b :init-keyword :b :accessor b-b)))
(define-method write-object ((b <b>) port)
(let* ((j (b-b b))
(k 1000.0)
(l '(byte k M G T P E Z Y))
(m (min (truncate->exact (/ (log j) (log k)))
(- (length l) 1))))
(if (< j k)
(display j)
(display (/ (truncate (* (/ j (expt k m)) 10)) 10)))
(print (list-ref l m))))
(define (main args)
(display "input: ")(flush)
(print (make <b> :b (x->number(read)))))
|
81B。
1 2 3 4 5 6 | /^..\?.\?$/b
s/$/.0kMGT/
:a
s/\(.\)\(.\)..\...\(.\)/\1.\2\3/
ta
s/\(\...\).*/\1/
|
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 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 | #include <iostream>
template <bool b, class T, class S> struct Choice { typedef T Result; };
template <class T, class S> struct Choice<false, T, S> { typedef S Result; };
struct None
{
enum { symbol = ' ' };
static double scaled(long long n) throw()
{ return static_cast<double>(n); }
};
struct Kilo
{
enum { symbol = 'K' };
static double scaled(long long n) throw()
{ return static_cast<double>(n) / 1000LL; }
};
struct Mega
{
enum { symbol = 'M' };
static double scaled(long long n) throw()
{ return static_cast<double>(n) / 1000000LL; }
};
struct Giga
{
enum { symbol = 'G' };
static double scaled(long long n) throw()
{ return static_cast<double>(n) / 1000000000LL; }
};
struct Tera
{
enum { symbol = 'T' };
static double scaled(long long n) throw()
{ return static_cast<double>(n) / 1000000000000LL; }
};
template <long long n>
struct SIPrefix
{
typedef
typename Choice< n < 1000LL, None,
typename Choice< n < 1000000LL, Kilo,
typename Choice< n < 1000000000LL, Mega,
typename Choice< n < 1000000000000LL, Giga,
Tera
>::Result>::Result>::Result>::Result Result;
};
template <long long n>
struct HumanReadable
{
private:
typedef typename SIPrefix<n>::Result prefix;
friend std::ostream& operator << (std::ostream& os, struct HumanReadable<n>)
{
os << prefix::scaled(n) << static_cast<char>(prefix::symbol);
}
};
int main()
{
std::cout << HumanReadable<123456789012345LL>() << std::endl;
return 0;
};
|
もっと純粋関数言語っぽくしてみました。g++だとこんなすさまじいのが通る。
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 | #include <iostream>
template <bool b, class T, class S> struct Choice { typedef T Result; };
template <class T, class S> struct Choice<false, T, S> { typedef S Result; };
struct None {enum{ symbol = ' ', base = 1LL };};
struct Kilo {enum{ symbol = 'K', base = 1000LL };};
struct Mega {enum{ symbol = 'M', base = 1000000LL };};
struct Giga {enum{ symbol = 'G', base = 1000000000LL };};
struct Tera {enum{ symbol = 'T', base = 1000000000000LL };};
template <long long n> struct SIPrefix
{
typedef
typename Choice< n < Kilo::base, None,
typename Choice< n < Mega::base, Kilo,
typename Choice< n < Giga |





takano32
#7310()
[
Ruby
]
Rating1/1=1.00
与えられたバイト数を読みやすくしてください。読みやすくとは、いわゆる human readable な表記とします(詳しくはサンプルのコードを参考にしてください)。
与えるバイト数についてはリテラルで与える、標準入力で与える、引数で与えるなどは自由とします。
余力のあるものはこのプログラムを短くしてください。
※ LL Future実行委員の高野光弘です。この出題は LL Future公式の出題であり、優れたものについてはLL Golfのセッションでご紹介させていただくかもしれません。ご理解の上、ご投稿ください。また、LL Futureのチケットは現在も発売中です。よろしければ、メインイベントの方にもぜひご参加ください。
Rating1/1=1.00-0+
[ reply ]