인생은 고통의 연속

4일차 리뷰 본문

프로그래밍/알고리즘

4일차 리뷰

gnidoc 2019. 1. 10. 23:32
    반응형

    2019/01/09 - [프로그래밍/알고리즘] - 3일차 리뷰


    step4는 if문


    어려운 문제는 없었지만 채점 시스템의 문제로 고통 받은 문제를 리뷰 ㅠㅠ




    4344번

    대학생 새내기들의 90%는 자신이 반에서 평균은 넘는다고 생각한다. 당신은 그들에게 슬픈 진실을 알려줘야 한다.

    첫째 줄에는 테스트 케이스의 개수 C가 주어진다.

    둘째 줄부터 각 테스트 케이스마다 학생의 수 N(1 ≤ N ≤ 1000, N은 정수)이 첫 수로 주어지고, 이어서 N명의 점수가 주어진다. 점수는 0보다 크거나 같고, 100보다 작거나 같은 정수이다.

    각 케이스마다 한 줄씩 평균을 넘는 학생들의 비율을 반올림하여 소수점 셋째 자리까지 출력한다.


    매우 슬픈 문제이자 날 고통스럽게한 문제이다.


    내 풀이 : https://github.com/gnidoc327/one-day-one-problem/blob/master/src/step_by_step/step4/Problem4344/Main.java


    문제만 길지 그냥 평균 아래 인원 비율을 구하는 것이다.

    그런데 아래는 내가 고통 받았던 이유의 코드이다.

    1
    2
    3
    4
    5
    6
    7
    System.out.printf("%.3f"100.0 * loser / n);
    System.out.println("%");
     
    //같은 결과이지만 오답임
    //double result = 100.0 * loser / n;
    //result = Math.round(result * 1000) / 1000.0;
    //System.out.println(result + "%");
    cs


    결과인 백분율 값을 소수 3번째 자리로 반올림해서 출력하는 코드인데

    아래 주석코드가 처음에 작성하고 계속 틀렸던 부분이다.

    콘솔 코딩이 오랜만이라 printf가 있는지 까먹었지만 

    꼼수로 반올림&소수점자리 처리를 해서

    예제 결과와 똑같이 출력했다


    그런데 계속 오답인 것이다 ㄷㄷ



    왜 틀렸는지에 대한 최소한의 피드백(예제 케이스 정답 정도)이 없으니

    뭐가 문제인지 몰랐는데

    다른 사람들이 푼 정답을 보니 printf를 사용했다.

    그래서 나도 printf를 쓰니 정답이더라....(눙물)


    그래서 println과 printf를 까보았다

    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
    class PrintStream {
        // printf
        public PrintStream format(String format, Object ... args) {
            try {
                synchronized (this) {
                    ensureOpen();
                    if ((formatter == null)
                        || (formatter.locale() !=
                            Locale.getDefault(Locale.Category.FORMAT)))
                        formatter = new Formatter((Appendable) this);
                    formatter.format(Locale.getDefault(Locale.Category.FORMAT),
                                     format, args);
                }
            } catch (InterruptedIOException x) {
                Thread.currentThread().interrupt();
            } catch (IOException x) {
                trouble = true;
            }
            return this;
        }
     
        public PrintStream printf(String format, Object ... args) {
            return format(format, args);
        }
     
        // println
        private void write(String s) {
            try {
                synchronized (this) {
                    ensureOpen();
                    textOut.write(s);
                    textOut.flushBuffer();
                    charOut.flushBuffer();
                    if (autoFlush && (s.indexOf('\n'>= 0))
                        out.flush();
                }
            }
            catch (InterruptedIOException x) {
                Thread.currentThread().interrupt();
            }
            catch (IOException x) {
                trouble = true;
            }
        }
     
        public void print(String s) {
            write(String.valueOf(s));
        }
     
        public void println(String x) {
            synchronized (this) {
                print(x);
                newLine();
            }
        }
    cs

    대충 보면 

    printf는 format() -> formatter.format()으로 출력하고

    println은 print() -> write()로 출력한다.


    제대로 보면

    printf의 format은 PrintStream의 멤버변수인 formatter의 format 호출해서 출력하는데

    formatter의 format을 또 파고 들어가면 

    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
    class Formatter{
        public Formatter format(Locale l, String format, Object ... args) {
            ensureOpen();
     
            // index of last argument referenced
            int last = -1;
            // last ordinary index
            int lasto = -1;
     
            List<FormatString> fsa = parse(format);
            for (FormatString fs : fsa) {
                int index = fs.index();
                try {
                    switch (index) {
                    case -2:  // fixed string, "%n", or "%%"
                        fs.print(null, l);
                        break;
                    case -1:  // relative index
                        if (last < 0 || (args != null && last > args.length - 1))
                            throw new MissingFormatArgumentException(fs.toString());
                        fs.print((args == null ? null : args[last]), l);
                        break;
                    case 0:  // ordinary index
                        lasto++;
                        last = lasto;
                        if (args != null && lasto > args.length - 1)
                            throw new MissingFormatArgumentException(fs.toString());
                        fs.print((args == null ? null : args[lasto]), l);
                        break;
                    default:  // explicit index
                        last = index - 1;
                        if (args != null && last > args.length - 1)
                            throw new MissingFormatArgumentException(fs.toString());
                        fs.print((args == null ? null : args[last]), l);
                        break;
                    }
                } catch (IOException x) {
                    lastException = x;
                }
            }
            return this;
        }
     
        private interface FormatString {
            int index();
            void print(Object arg, Locale l) throws IOException;
            String toString();
        }
     
        private class FixedString implements FormatString {
            private String s;
            private int start;
            private int end;
            FixedString(String s, int start, int end) {
                this.s = s;
                this.start = start;
                this.end = end;
            }
            public int index() { return -2; }
            public void print(Object arg, Locale l)
                throws IOException { a.append(s, start, end); }
            public String toString() { return s.substring(start, end); }
        }
    }
    cs

    inner class인 formatString의 print를 사용해서 출력한다.

    하지만 formatString은 interface이고 

    실제로는 10번째 줄 parse에서 FixedString class를 사용한다.

    그래서 실제로 출력하는 FixedString.print를 보아하니(61번째 줄)

    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
    class Formatter {
        private Appendable a;    // a = PrintStream
     
        public void print(Object arg, Locale l) throws IOException { 
            a.append(s, start, end); 
        }
     
    class PrintStream {
        public PrintStream format(String format, Object ... args) {
            try {
                synchronized (this) {
                    ensureOpen();
                    if ((formatter == null)
                        || (formatter.locale() !=
                            Locale.getDefault(Locale.Category.FORMAT)))
                        formatter = new Formatter((Appendable) this);
                    formatter.format(Locale.getDefault(Locale.Category.FORMAT),
                                     format, args);
                }
            } catch (InterruptedIOException x) {
                Thread.currentThread().interrupt();
            } catch (IOException x) {
                trouble = true;
            }
            return this;
        }
     
        public PrintStream append(CharSequence csq) {
            print(String.valueOf(csq));
            return this;
        }
    }
    cs

    그럼 저 a는 뭐였냐 바로 PrintStream(this)이다.

    그럼 PrintStream의 append를 가보면....?

    println과 같은 print를 사용하지만 String.valueOf(csq)로 출력한다.


    정리해보자면

    printf() => print(String.valueOf(csq))

    println() => print(String x)

    이거다.


    print에서 write를 부를때 String.valueOf()를 무조건 호출하므로 다른 객체(타입)가 아니다.

    new line(\n)에 대한 문제도 아닌게 "%"를 똑같이 println으로 출력해도 다르다는 것이다.


    그런데 생각해보니 오답으로 나오는 부분은 내가 double로 출력했고

    정답으로 나오는 부분은 float으로 출력했다.

    double이 더 긴 소수점 보증해주는 타입인데

    오히려 이걸 사용하므로써 오차가 생긴거 아닐까? 라는 생각이 들긴했다.

    왜냐하면 컴퓨터의 소수점 계산은 약간 부정확하고 

    cpu에 따라서 계산이 다를 수도 있기 때문이다.


    백준 알고리즘 사이트가 aws를 사용하는걸로 아는데 amd서버라면 

    intel cpu를 쓰는 내 컴퓨터와 결과가 다를 수도 있겠지....

    가 내 결론이었다.


    테스트하기는 케이스 찾기가 어려우니 앞으로 float 연산에서는 최대한 float만 쓰는걸로....

    아 알고리즘 빡세다

    반응형

    '프로그래밍 > 알고리즘' 카테고리의 다른 글

    6일차 리뷰  (0) 2019.01.12
    5일차 리뷰  (0) 2019.01.12
    3일차 리뷰  (0) 2019.01.09
    1, 2일차 리뷰  (0) 2019.01.08
    백준 알고리즘  (0) 2019.01.07
    Comments