challenge 与えられた数字のケタ数

与えられた数字のケタ数と、最大桁の位を求めてください。
数字が2469なら4桁で最大桁は1000の位です。
600なら3と100、1なら1と1です。

このお題はsusuさんの投稿です。ご投稿ありがとうございます。

Posted feedbacks - Flatten

Nested Hidden
0が入力されたときは、 ケタ数1、最大桁の位1で良かったでしょうか。
 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
#include <stdio.h>
#include <math.h>

int main()
{
    unsigned long input_data;
    int           digit;

    printf("正の整数を入力してください : ");
    scanf("%ld", &input_data);

    /* 0と入力されたとき対策 */
    if (input_data != 0) {
        digit = 0;
    }
    else {
        digit = 1;
    }

    while (input_data > 0) {
        input_data /= 10;
        digit++;
    }

    printf("ケタ数     : %d\n", digit);
    printf("最大桁の位 : %d\n", (int)pow(10, digit-1));

    return 0;
}

bashで王道?に。
1
2
3
#!/bin/bash
n="$1"
echo "$nは${#n}桁で最大桁は$((10**(${#n}-1)))の位です。"

負の値の場合、"-"は桁数に入らないですよね?
最大桁に同じものがあったときは、1の位に近いものを出しています。

> digit_max(600)
digits = 3 
max digit = 100 
> digit_max(-600)
digits = 3 
max digit = 100 
> digit_max(0)
digits = 1 
max digit = 1 
1
2
3
4
5
digit_max <- function(x){
    if(x < 0) x <- x * -1
    cat("digits =", ifelse(x==0, 1, floor(log(x, 10))+1), "\n")
    cat("max digit =", 10 ** (which.max(rev(as.integer(unlist(strsplit(as.character(x), ""))))) - 1), "\n")
}

ワンライナーで.

実行例:

> perl -e '$l = length($ARGV[0]); print $l, "\n", 10 ** ($l-1), "\n"' 1
1
1

> perl -e '$l = length($ARGV[0]); print $l, "\n", 10 ** ($l-1), "\n"' 600
3
100

> perl -e '$l = length($ARGV[0]); print $l, "\n", 10 ** ($l-1), "\n"' 2469
4
1000

1
perl -e '$l = length($ARGV[0]); print $l, "\n", 10 ** ($l-1), "\n"' 1

(figure 2469)
 => 4
 => 1000

(figure 600)
 => 3
 => 100

(figure 1)
 => 1
 => 1
1
2
3
4
5
6
(defun figure (n)
  (and (plusp n)
       (let ((fig (ceiling (log n 10))))
         (if (zerop fig)
             (values 1 1)
           (values fig (expt 10 (1- fig)))))))

・・・あ、最大桁って最大の数字を含む桁じゃないんですね。すみません。
数学風にlogを使う方法と、スクリプト言語風に文字数をカウントする方法を使ってます。

> digit_max(-12345)
digits = 5 
max digit = 10000
1
2
3
4
5
digit_max <- function(x){
    if(x < 0) x <- x * -1
    cat("digits =", ifelse(x==0, 1, floor(log(x, 10))+1), "\n")
    cat("max digit =", 10 ** (nchar(as.character(x))-1), "\n")
}

いかんいかん。端折り過ぎたorz

(figure 2469)
 => 4
 => 1000

(figure 600)
 => 3
 => 100

(figure 1)
 => 1
 => 1

(figure 0)
 => 1
 => 1

(figure -2469)
 => 4
 => 1000
1
2
3
4
5
6
(defun figure (n)
  (cond ((zerop n) (values 1 1))
        (t (let ((fig (ceiling (log (abs n) 10))))
             (if (zerop fig)
                 (values 1 1)
               (values fig (expt 10 (1- fig))))))))

何も考えずに超簡単に。
(4, 1000)
(3, 100)
(8, 10000000)
(6, 100000)
(7, 1000000)
(1, 1)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
def getKetaAndKurai(num):
    s = str(num)
    keta = len(s)
    kurai = int("1" + "0" * (keta - 1))

    return (keta, kurai)

print getKetaAndKurai(2469)
print getKetaAndKurai(600)
print getKetaAndKurai(12378990)
print getKetaAndKurai(414879)
print getKetaAndKurai(3141592)
print getKetaAndKurai(1)


	
1
2
3
4
function figure(x){
  y = size(string(int(x)))
  [y, pow(10,y-1)]
}

ぜんぜん考えてません。0のときこうなりました。
(digits 0)
=>0
=>1/10
1
2
3
4
5
6
(define (digits n)
  (define (f n)
    (if (zero? n) 0
        (+ 1 (f (quotient n 10)))))
  (let1 digit (f n)
    (values digit (expt 10 (- digit 1)))))

文字上の桁数を数えています。
Prologの人気のなさに絶望した。
ところで、0は一桁、でいいんでしょうかね。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
val(X,_,X).

figure(N,(K,X)):-
        atom_chars(N,N1),
        length(N1,K),
        maplist(val('0'),N1,[_|N2]),
        atom_chars(X,['1'|N2]).

:-maplist(figure,[1234,1,0],X),writeln(X).
% 実行結果
% [ (4, 1000), (1, 1), (1, 1)]

そこそこ丁寧に
1
2
3
4
function figure(x){
	var len=Math.abs(parseInt(x,10)).toString().length;
	return [len,Math.pow(10,len-1)];
}

ex) 
> gawk -fketa.awk 16
2 10

>gawk -fketa.awk 00065536
5 10000

数字の先頭に0がついていない前提なら4行目は不要です。
1
2
3
4
5
6
7
8
9
BEGIN {
	value = ARGV[1]

	value = gensub(/^0*([0-9]+)$/, "\\1", "", value)
	keta = length(value)
	max = "1"
	for(i = 0; i < keta - 1; i++) { max = max "0" }
	print keta, max
}

1
2
3
4
def solve(n:int) = {
  val w = n.toString.length
  (w, Math.pow(10, w-1).toInt)
}

accumulator 変数2つも要らないのでは?と思われるかもしれませんが OCaml で 10 ** len をやろうと思うとかっこ悪いことになるので…
1
2
3
4
5
6
let num_digits n =
  let rec num_digits' len place = function
  | 0 -> (len, place)
  | n -> num_digits' (succ len) (place * 10) (n / 10)
  in
  num_digits' 1 1 (n / 10)

とりあえず。
1
f = lambda i: (len(str(i)), 10 ** (len(str(i)) - 1))

1
2
3
4
5
6
function keta(num) {
    for(var n = 0;num >= 1;n++) {
        num /= 10;
    }   
    return [n, Math.pow(10, n-1)]
}

小数点以下の桁数をどう表現すればいいのか迷いましたが、マイナス方向にそのまま延長しています。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
import java.lang.StrictMath;

public class Sample {
    public static void keta(double num) {
        int keta = 0;
        if (num != 0) {
            keta = (int)StrictMath.log10(StrictMath.abs(num));
        }
        System.out.printf("%d, %g%n", keta + 1, StrictMath.pow(10.0, keta));
    }

    public static void main(String[] args) {
        keta(Double.parseDouble(args[0]));
    }
}

Squeak Smalltalk で。
1
2
3
4
5
| n numOfDigits |
n := 2469.
^{numOfDigits := n printString size. 10 raisedTo: numOfDigits - 1}

"=> #(4 1000) "

整数だけですが、桁数と位を返せるクラスをつくってみました。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public class DigitMain {

	public static void main(String[] args) {
		Digit digit = new Digit(2469);
		System.out.println(digit.getNumber() +":" + digit.getUnit());
	}
}


public class Digit {
	private static int value;

	public Digit(int value){
		this.value = value;
	}

	public int getNumber(){
		return String.valueOf(value).length();
	}

	public int getUnit(){
		return  getNumber() == 1 ? 1 : (int)(Math.pow(10, getNumber()-1));
	}
}

変数切りすぎかなぁ
1
2
3
4
5
6
def keta_kurai(num)
  keta = num.abs.truncate.to_s.length
  kurai = "1"
  kurai += "0" * (keta-1) if keta > 1
  return keta, kurai
end

なんでかloginできないので匿名アカウントで(n某)
1
2
3
import System.Environment 
starling f g x = f x (g x)
main = print . starling (,) ((10^) . subtract 1) . length . head =<< getArgs

DrSchemeにて。
> (digits-and-msd 1)
(1 . 1)
> (digits-and-msd 600)
(3 . 100)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
(define (digits-and-msd number)
  (cons (digits number) (msd number)))

(define (msd number)
  (power 10 (- (digits number) 1)))

(define (digits number)
  (cond ((< number 10) 1)
        (else (+ 1 (digits (/ number 10))))))

(define (power base exp)
  (cond ((= exp 0) 1)
        ((= exp 1) base)
        (else (* base (power base (- exp 1))))))

0とか負数のときはどうすればいいんだろう。適当に処理しておいたけど。
 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
#!/usr/bin/env python                                                                                                                                                            
# -*- coding: utf-8 -*-                                                                                                                                                          

import sys

def digits(n):
    """                                                                                                                                                                          
    returns count of digits and order of most siginificant digit.                                                                                                                
                                                                                                                                                                                 
    >>> digits(2469)                                                                                                                                                             
    (4, 1000)                                                                                                                                                                    
                                                                                                                                                                                 
    >>> digits(600)                                                                                                                                                              
    (3, 100)                                                                                                                                                                     
                                                                                                                                                                                 
    >>> digits(1)                                                                                                                                                                
    (1, 1)                                                                                                                                                                       
                                                                                                                                                                                 
    >>> digits(0)                                                                                                                                                                
    (1, 1)                                                                                                                                                                       
                                                                                                                                                                                 
    >>> digits(-100)                                                                                                                                                             
    (3, 100)                                                                                                                                                                     
    """
    if n < 0:
        n = -n
    s = str(n)
    return (len(s), 10 ** (len(s) - 1))

def _test():
    import doctest
    doctest.testmod()

if __name__ == '__main__':
    _test()

整数限定にしておきました。
1
2
3
4
5
6
7
Public Sub foo(ByVal number As Integer)

    Dim length As Integer = number.ToString.Replace("-", "").Length
    Console.WriteLine(length)
    Console.WriteLine(10 ^ (length - 1))

End Sub

初めて投稿します。
1
2
3
4
BEGIN {
	keta = length(0 + ARGV[1])
	print keta, 10**(keta - 1)
}

awkで書いたやつと同じやり方ですが

gosh> (keta+kurai 12345678)
8
10000000
1
2
3
(define (keta+kurai n)
  (let1 keta (string-length (number->string n))
		(values keta (expt 10 (- keta 1)))))

VisualWorks で。 作った後 sumim さんのをみて、そうだ、文字列にして文字数数えればいいんじゃん... と 自分の頭の固さにガッカリです。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
| getDigitsAndPlace |
getDigitsAndPlace :=
    [ :var | 
        | func |
        func := [ :x :d |
                    (10 ** d) <= x
                        ifTrue: [func value: x value: d + 1]
                        ifFalse: [ Array with: d with: 10 ** (d-1)]].
        func value: var value: 0].


Transcript cr; show: (getDigitsAndPlace value: 2649) printString;
           cr; show: (getDigitsAndPlace value: 1) printString;
           cr; show: (getDigitsAndPlace value: 600) printString

"== 結果 ==
#(4 1000)
#(1 1)
#(3 100)
"

あー、、いきなりヘッポコ、自己レスです。

x はレキシカル変数にでいいですね。自分のヘッポコぶりに絶望した!
1
2
3
4
5
6
7
8
9
| getDigitsAndPlace |
getDigitsAndPlace :=
    [ :x |  
        | func  |
        func := [ :d |
                    (10 ** d) <= x
                        ifTrue: [func value: d + 1]
                        ifFalse: [ Array with: d with: 10 ** (d-1)]].
        func value: 0].

常用対数でやってみました。

使用例:
>> [d,m] = doukaku40(321321)
d =
     6
m =
      100000
1
2
3
function [d,m] = doukaku40(n)
  d = floor(log10(n)) + 1;
  m = 10^(d-1);

でも、これだとゼロとかマイナス値のときに破綻しますね。要・再検討。

log使うのは、誤差が入るので、ループでカウントすべきですが、、、
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
using System;
class Program
{
  static void Main()
  {
    ShowDigit(2469);
    ShowDigit(600);
    ShowDigit(1);
  }
  static void ShowDigit(int k)
  {
    int n = (int)Math.Log10(k);
    Console.WriteLine("{0} {1}", n + 1, Math.Pow(10, n));
  }
}

例えば1.23の最大桁の位を1とするのか1.00とするのか、、
多分1だと思うのですが、とりあえず両方ともできるようにしてみました。
あと、powを使うのが一番楽ですが、php(?)らしく数値を文字列操作する妙な方法でやってみました。

//1.23 の入力で最大桁数を 1と表示するなら
1->     1 1
600->   3 100
9999->  4 1000
0->     1 1
-1->    1 1
-600->  3 100
-9999-> 4 1000
1.23->  4 1
-9.99-> 4 1
abc->   error 

//1.23 の入力で最大桁数を 1.00と表示するなら
1->     1 1
600->   3 100
9999->  4 1000
0->     1 1
-1->    1 1
-600->  3 100
-9999-> 4 1000
1.23->  4 1.00
-9.99-> 4 1.00
abc->   error 
 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
<?php

function check($input)
{
	//入力が数値以外ならエラー
	if(!is_numeric($input))
	{
		return array("error");
	}

	//0より小さい(マイナスだったら)+にする
	if($input<0)
	{
		$input=$input*-1;
	}

//1.23 の入力で最大桁数を 1.00と表示するなら
//	//全ての数値を0にする
//	$max_kurai=ereg_replace("[0-9]","0",$input);
//	//先頭文字を切り捨てた文字列の先頭に'1'をつなげる
//	$max_kurai="1".substr($max_kurai,1,10000000000000);

//1.23 の入力で最大桁数を 1と表示するなら
	//全ての桁を9にする
	$max_kurai=ereg_replace("[0-9]","9",(int)$input);
	//1を足して10で割る  9999 -> 10000 -> 1000
	$max_kurai=($max_kurai+1)/10;	

//1.23 の入力で最大桁数を 1と表示するなら powを使う
//	$max_kurai=pow(10,strlen((int)$input)-1);


	return array(strlen($input),$max_kurai);
}

echo "<pre>";
$target=1;	$ret=check($target);	echo $target."->\t".$ret[0]." ".$ret[1]."\n";
$target=600;	$ret=check($target);	echo $target."->\t".$ret[0]." ".$ret[1]."\n";
$target=9999;	$ret=check($target);	echo $target."->\t".$ret[0]." ".$ret[1]."\n";
$target=0;	$ret=check($target);	echo $target."->\t".$ret[0]." ".$ret[1]."\n";
                                                                         
$target=-1;	$ret=check($target);	echo $target."->\t".$ret[0]." ".$ret[1]."\n";
$target=-600;	$ret=check($target);	echo $target."->\t".$ret[0]." ".$ret[1]."\n";
$target=-9999;	$ret=check($target);	echo $target."->\t".$ret[0]." ".$ret[1]."\n";
                                                                         
$target=9.99;	$ret=check($target);	echo $target."->\t".$ret[0]." ".$ret[1]."\n";
$target=-9.99;	$ret=check($target);	echo $target."->\t".$ret[0]." ".$ret[1]."\n";
                                                                         
$target="abc";	$ret=check($target);	echo $target."->\t".$ret[0]." ".$ret[1]."\n";

?>

しまった。この手がありました。
> (digit-number 316)
(3 . 100)
> (digit-number 1)
(1 . 1)
1
2
3
4
(define (digit-number number)
  (define (digits n) (string-length (number->string n)))
  (let ((d (digits number)))
        (cons d (expt 10 (- d 1)))))

JS版みてアッと思い、abs追加して晒しです。小数点以下はバッサリいってます。
1
2
3
4
function ketasu(num:Number):Array{
	var keta:Number = Math.abs(Math.floor(num)).toString().length;
	return(new Array(keta,Math.pow(10,keta-1)));
}

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
public class GetKeta {

    /** 桁数取得. */
    public static int getKeta(int value) {
        return String.valueOf(value).length();
    }

    /** 位. */
    public static int getUnit(int value) {
        return (int) Math.pow(10d, (double) getKeta(value) - 1);
    }

}

>og使うのは、誤差が入るので、ループでカウントすべき

なるほど。

log10の誤差で答えが間違いになる例を調べてみました。

>>> x = 999999999999999
>>> log10(x) + 1
16.0
>>> len(str(x))
15

double では有効桁数が足りない場合があるという(他言語での)指摘を受けて BigDecimal を使ってみました。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
import java.math.BigDecimal;
import java.math.MathContext;

public class Sample2 {
    public static void keta(BigDecimal num) {
        int keta = num.precision() - num.scale();
        MathContext ctx = MathContext.DECIMAL32;
        System.out.printf("%d, %g%n", keta, BigDecimal.TEN.pow(keta - 1, ctx));
    }

    public static void main(String[] args) {
        keta(new BigDecimal(args[0]));
    }
}

うーん、素晴らしいコードだとは口が裂けたら言えないけど、マイナス評価喰らうほどひどいかなぁ…
#ifじゃなくてcond使ってる辺りはヒドイが(ぉ
##pluspとminuspの振り分けをabsで吸収するまでのアレコレで残っちゃったんだよね。

評価そのものより、評価理由がキニナル(´・ω・`)

あえて数字を文字列にしない方向で
1
keta x = snd $ head $ filter (\(y,z)-> y > x) $ zip (iterate (*10) 10) $ zip [1..] $ iterate (*10) 1

カリー化でちょっとだけ短く
1
keta x = snd $ head $ filter ((>x).fst) $ zip (iterate (*10) 10) $ zip [1..] $ iterate (*10) 1