Middle three digits

From Rosetta Code
Revision as of 01:08, 4 February 2013 by rosettacode>Bearophile (First D entry: shorter line, tags)
Task
Middle three digits
You are encouraged to solve this task according to the task description, using any language you may know.

The task is to:

Write a function/procedure/subroutine that is called with an integer value and returns the middle three digits of the integer if possible or a clear indication of an error if this is not possible.

Your function should be tested with the following values; the first line should return valid answers, those of the second line should return clear indications of an error:

123, 12345, 1234567, 987654321, 10001, -10001, -123, -100, 100, -12345
1, 2, -1, -10, 2002, -2002, 0

Show your output on this page.

D

<lang d>import std.stdio, std.traits, std.conv;

string middleThreeDigits(T)(in T n) if (isIntegral!T) {

   auto s = n < 0 ? n.text()[1 .. $] : n.text();
   auto len = s.length;
   if (len < 3 || len % 2 == 0)
       return "Need odd and >= 3 digits";
   auto mid = len / 2;
   return s[mid - 1 .. mid + 2];

}

void main() {

   immutable passing = [123, 12345, 1234567, 987654321, 10001, -10001,
           -123, -100, 100, -12345, long.min, long.max];
   foreach (n; passing)
       writefln("middleThreeDigits(%s): %s", n, middleThreeDigits(n));
   immutable failing = [1, 2, -1, -10, 2002, -2002, 0,int.min,int.max];
   foreach (n; failing)
       writefln("middleThreeDigits(%s): %s", n, middleThreeDigits(n));

}</lang>

Output:
middleThreeDigits(123): 123
middleThreeDigits(12345): 234
middleThreeDigits(1234567): 345
middleThreeDigits(987654321): 654
middleThreeDigits(10001): 000
middleThreeDigits(-10001): 000
middleThreeDigits(-123): 123
middleThreeDigits(-100): 100
middleThreeDigits(100): 100
middleThreeDigits(-12345): 234
middleThreeDigits(-9223372036854775808): 368
middleThreeDigits(9223372036854775807): 368
middleThreeDigits(1): Need odd and >= 3 digits
middleThreeDigits(2): Need odd and >= 3 digits
middleThreeDigits(-1): Need odd and >= 3 digits
middleThreeDigits(-10): Need odd and >= 3 digits
middleThreeDigits(2002): Need odd and >= 3 digits
middleThreeDigits(-2002): Need odd and >= 3 digits
middleThreeDigits(0): Need odd and >= 3 digits
middleThreeDigits(-2147483648): Need odd and >= 3 digits
middleThreeDigits(2147483647): Need odd and >= 3 digits

Alternative Version

This longer version gives a stronger typed output, and it tries to be faster avoiding conversions to string. <lang d>import std.stdio, std.traits, std.math, std.variant;

/// Returns a string with the error, or the three digits. Algebraic!(string, char[3]) middleThreeDigits(T)(in T n) if (isIntegral!T) {

   // Awkward code to face abs(T.min) when T is signed.
   ulong ln;
   static if (isSigned!T) {
       if (n >= 0) {
           ln = n;
       } else {
           if (n == T.min) {
               ln = -(n + 1);
               ln++;
           } else {
               ln = -n;
           }
       }
   } else {
       ln = n;
   }
   if (ln < 100)
       return typeof(return)("n is too short.");
   immutable uint digits = 1 + cast(uint)log10(ln);
   if (digits % 2 == 0)
       return typeof(return)("n must have an odd number of digits.");
   // From the Reddit answer by "millstone".
   int drop = (digits - 3) / 2;
   while (drop-- > 0)
       ln /= 10;
   char[3] result = void;
   result[2] = ln % 10 + '0';
   ln /= 10;
   result[1] = ln % 10 + '0';
   ln /= 10;
   result[0] = ln % 10 + '0';
   return typeof(return)(result);

}

void main() {

   immutable passing = [123, 12345, 1234567, 987654321, 10001,
                        -10001, -123, -100, 100, -12345, -8765432];
   foreach (n; passing) {
       auto mtd = middleThreeDigits(n);
       // A string result means it didn't pass.
       assert(!mtd.peek!string);
       writefln("middleThreeDigits(%d): %s", n, mtd);
   }
   writeln();
   immutable failing = [1, 2, -1, -10, 2002, -2002, 0,
                        15, int.min, int.max];
   foreach (n; failing) {
       auto mtd = middleThreeDigits(n);
       assert(mtd.peek!string);
       writefln("middleThreeDigits(%d): %s", n, mtd);
   }
   writeln();
   immutable long[] passingL = [123, 12345, 1234567, 987654321, 10001,
                                -10001, -123, -100, 100, -12345,
                                -8765432, long.min, long.max];
   foreach (n; passingL) {
       auto mtd = middleThreeDigits(n);
       assert(!mtd.peek!string);
       writefln("middleThreeDigits(%d): %s", n, mtd);
   }
   writeln();
   immutable long[] failingL = [1, 2, -1, -10, 2002, -2002, 0, 15];
   foreach (n; failingL) {
       auto mtd = middleThreeDigits(n);
       assert(mtd.peek!string);
       writefln("middleThreeDigits(%d): %s", n, mtd);
   }
   writeln();
   {
       immutable n = short.min;
       auto mtd = middleThreeDigits(n);
       assert(!mtd.peek!string);
       writefln("middleThreeDigits(cast(short)%d): %s", n, mtd);
   }

}</lang>

Output:
middleThreeDigits(123): 123
middleThreeDigits(12345): 234
middleThreeDigits(1234567): 345
middleThreeDigits(987654321): 654
middleThreeDigits(10001): 000
middleThreeDigits(-10001): 000
middleThreeDigits(-123): 123
middleThreeDigits(-100): 100
middleThreeDigits(100): 100
middleThreeDigits(-12345): 234
middleThreeDigits(-8765432): 654

middleThreeDigits(1): n is too short.
middleThreeDigits(2): n is too short.
middleThreeDigits(-1): n is too short.
middleThreeDigits(-10): n is too short.
middleThreeDigits(2002): n must have an odd number of digits.
middleThreeDigits(-2002): n must have an odd number of digits.
middleThreeDigits(0): n is too short.
middleThreeDigits(15): n is too short.
middleThreeDigits(-2147483648): n must have an odd number of digits.
middleThreeDigits(2147483647): n must have an odd number of digits.

middleThreeDigits(123): 123
middleThreeDigits(12345): 234
middleThreeDigits(1234567): 345
middleThreeDigits(987654321): 654
middleThreeDigits(10001): 000
middleThreeDigits(-10001): 000
middleThreeDigits(-123): 123
middleThreeDigits(-100): 100
middleThreeDigits(100): 100
middleThreeDigits(-12345): 234
middleThreeDigits(-8765432): 654
middleThreeDigits(-9223372036854775808): 368
middleThreeDigits(9223372036854775807): 368

middleThreeDigits(1): n is too short.
middleThreeDigits(2): n is too short.
middleThreeDigits(-1): n is too short.
middleThreeDigits(-10): n is too short.
middleThreeDigits(2002): n must have an odd number of digits.
middleThreeDigits(-2002): n must have an odd number of digits.
middleThreeDigits(0): n is too short.
middleThreeDigits(15): n is too short.

middleThreeDigits(cast(short)-32768): 276

J

Solution: <lang j>asString=: ":"0 NB. convert vals to strings getPfxSize=: [: -: 3 -~ # NB. get size of prefix to drop before the 3 middle digits getMid3=: (3 {. 'err' ,~ getPfxSize }. ]) :: ('err'"_) NB. get 3 middle digits or return 'err' getMiddle3=: getMid3@asString@:|</lang> Example: <lang j> vals=: 123 12345 1234567 987654321 10001 _10001 _123 _100 100 _12345 1 2 _1 _10 2002 _2002 0

  getMiddle3 vals

123 234 345 654 000 000 123 100 100 234 err err err err err err err</lang>

OCaml

<lang ocaml>let even x = (x land 1) <> 1

let middle_three_digits x =

 let s = string_of_int (abs x) in
 let n = String.length s in
 if n < 3 then failwith "need >= 3 digits" else
 if even n then failwith "need odd number of digits" else
 String.sub s (n / 2 - 1) 3

let passing = [123; 12345; 1234567; 987654321; 10001; -10001; -123; -100; 100; -12345] let failing = [1; 2; -1; -10; 2002; -2002; 0]

let print x =

 let res =
   try (middle_three_digits x)
   with Failure e -> "failure: " ^ e
 in
 Printf.printf "%d: %s\n" x res

let () =

 print_endline "Should pass:";
 List.iter print passing;
 print_endline "Should fail:";
 List.iter print failing;
</lang>
Output:
Should pass:
123: 123
12345: 234
1234567: 345
987654321: 654
10001: 000
-10001: 000
-123: 123
-100: 100
100: 100
-12345: 234

Should fail:
1: failure: need >= 3 digits
2: failure: need >= 3 digits
-1: failure: need >= 3 digits
-10: failure: need >= 3 digits
2002: failure: need odd number of digits
-2002: failure: need odd number of digits
0: failure: need >= 3 digits

Perl 6

<lang Perl6>sub middle-three($n) {

   given $n.abs {
       when .chars < 3  { "$n is too short" }
       when .chars %% 2 { "$n has an even number of digits" }
       default          { "The three middle digits of $n are: ", .substr: (.chars - 3)/2, 3 }
   }

}

say middle-three($_) for <

   123 12345 1234567 987654321 10001 -10001 -123 -100 100 -12345
   1 2 -1 -10 2002 -2002 0

>;</lang>

Output:
The three middle digits of 123 are:  123
The three middle digits of 12345 are:  234
The three middle digits of 1234567 are:  345
The three middle digits of 987654321 are:  654
The three middle digits of 10001 are:  000
The three middle digits of -10001 are:  000
The three middle digits of -123 are:  123
The three middle digits of -100 are:  100
The three middle digits of 100 are:  100
The three middle digits of -12345 are:  234
1 is too short
2 is too short
-1 is too short
-10 is too short
2002 has an even number of digits
-2002 has an even number of digits
0 is too short

Python

<lang python>>>> def middle_three_digits(i): s = str(abs(i)) length = len(s) assert length >= 3 and length % 2 == 1, "Need odd and >= 3 digits" mid = length // 2 return s[mid-1:mid+2]

>>> passing = [123, 12345, 1234567, 987654321, 10001, -10001, -123, -100, 100, -12345] >>> failing = [1, 2, -1, -10, 2002, -2002, 0] >>> for x in passing + failing: try: answer = middle_three_digits(x) except AssertionError as error: answer = error print("middle_three_digits(%s) returned: %r" % (x, answer))


middle_three_digits(123) returned: '123' middle_three_digits(12345) returned: '234' middle_three_digits(1234567) returned: '345' middle_three_digits(987654321) returned: '654' middle_three_digits(10001) returned: '000' middle_three_digits(-10001) returned: '000' middle_three_digits(-123) returned: '123' middle_three_digits(-100) returned: '100' middle_three_digits(100) returned: '100' middle_three_digits(-12345) returned: '234' middle_three_digits(1) returned: AssertionError('Need odd and >= 3 digits',) middle_three_digits(2) returned: AssertionError('Need odd and >= 3 digits',) middle_three_digits(-1) returned: AssertionError('Need odd and >= 3 digits',) middle_three_digits(-10) returned: AssertionError('Need odd and >= 3 digits',) middle_three_digits(2002) returned: AssertionError('Need odd and >= 3 digits',) middle_three_digits(-2002) returned: AssertionError('Need odd and >= 3 digits',) middle_three_digits(0) returned: AssertionError('Need odd and >= 3 digits',) >>> </lang>

REXX

<lang rexx>/* REXX ***************************************************************

  • 03.02.2013 Walter Pachl
                                                                                                                                            • /

sl='123 12345 1234567 987654321 10001 -10001 -123 -100 100 -12345',

  '2 -1 -10 2002 -2002 0 abc 1e3 -17e-3'

Do While sl<> /* loop through test values */

 Parse Var sl s sl                    /* pick next value            */
 Call mid3 s                          /* test it                    */
 End

Exit mid3: Procedure Parse arg d /* take the argument */ Select /* first test for valid input */

 When datatype(d)<>'NUM'   Then Call error 'not a number'
 When pos('E',translate(d))>0 Then Call error 'not just digits'
 When length(abs(d))<3     Then Call error 'less than 3 digits'
 When length(abs(d))//2<>1 Then Call error 'not an odd number of digits'
 Otherwise Do                         /* input is ok                */
   dx=abs(d)                          /* get rid of optional sign   */
   ld=length(dx)                      /* length of digit string     */
   z=(ld-3)/2                         /* number of digits to cut    */
   Say left(d,12) '->' substr(dx,z+1,3) /* show middle 3 digits     */
   End
 End
 Return

error:

 Say left(d,12) '->' arg(1)           /* tell about the problem     */
 Return

</lang> Output:

123          -> 123
12345        -> 234
1234567      -> 345
987654321    -> 654
10001        -> 000
-10001       -> 000
-123         -> 123
-100         -> 100
100          -> 100
-12345       -> 234
2            -> less than 3 digits
-1           -> less than 3 digits
-10          -> less than 3 digits
2002         -> not an odd number of digits
-2002        -> not an odd number of digits
0            -> less than 3 digits
abc          -> not a number
1e3          -> not just digits
-17e-3       -> not just digits

Rust

<lang rust>fn middle_three_digits(x: int) -> Result<~str, ~str> {

   let s = int::abs(x).to_str();
   let len = s.len();
   if len < 3 {
       Err(~"Too short")
   } else if len % 2 == 0 {
       Err(~"Even number of digits")
   } else {
       Ok(s.slice(len/2 - 1, len/2 + 2))
   }

}

fn print_result(x: int) {

   io::print(fmt!("middle_three_digits(%?) returned: ", x));
   match middle_three_digits(x) {
       Ok(move s) => io::println(fmt!("Success, %s", s)),
       Err(move s) => io::println(fmt!("Failure, %s", s))
   }

}

fn main() {

   let passing = [123, 12345, 1234567, 987654321, 10001, -10001, -123, -100, 100, -12345];
   let failing = [1, 2, -1, -10, 2002, -2002, 0];
   for passing.each |i| {
       print_result(*i);
   }
   for failing.each |i| {
       print_result(*i);
   }

}</lang>

Output:

middle_three_digits(123) returned: Success, 123
middle_three_digits(12345) returned: Success, 234
middle_three_digits(1234567) returned: Success, 345
middle_three_digits(987654321) returned: Success, 654
middle_three_digits(10001) returned: Success, 000
middle_three_digits(-10001) returned: Success, 000
middle_three_digits(-123) returned: Success, 123
middle_three_digits(-100) returned: Success, 100
middle_three_digits(100) returned: Success, 100
middle_three_digits(-12345) returned: Success, 234
middle_three_digits(1) returned: Failure, Too short
middle_three_digits(2) returned: Failure, Too short
middle_three_digits(-1) returned: Failure, Too short
middle_three_digits(-10) returned: Failure, Too short
middle_three_digits(2002) returned: Failure, Even number of digits
middle_three_digits(-2002) returned: Failure, Even number of digits
middle_three_digits(0) returned: Failure, Too short

Vedit macro language

<lang vedit>do {

   #1 = Get_Num("Enter a number, or 0 to stop: ", STATLINE)
   Ins_Text("Input: ") Num_Ins(#1, COUNT, 10)
   Call("MIDDLE_3_DIGITS")
   Ins_Text("  Result: ") Reg_Ins(10) Ins_Newline
   Update()

} while (#1); Return

// Find middle 3 digits of a number // in: #1 = numeric value // out: @10 = the result, or error text //

MIDDLE_3_DIGITS:

Buf_Switch(Buf_Free) Num_Ins(abs(#1), LEFT+NOCR) // the input value as string

  1. 2 = Cur_Col-1 // #2 = number of digits

if (#2 < 3) {

   Reg_Set(10, "Too few digits!")

} else {

   if ((#2 & 1) == 0) {

Reg_Set(10, "Not odd number of digits!")

   } else {

Goto_Pos((#2-3)/2) Reg_Copy_Block(10, Cur_Pos, Cur_Pos+3)

   }

} Buf_Quit(OK) Return </lang>

Output:

Input:        123  Result: 123
Input:      12345  Result: 234
Input:    1234567  Result: 345
Input:  987654321  Result: 654
Input:      10001  Result: 000
Input:     -10001  Result: 000
Input:       -123  Result: 123
Input:       -100  Result: 100
Input:        100  Result: 100
Input:     -12345  Result: 234
Input:          1  Result: Too few digits!
Input:          2  Result: Too few digits!
Input:         -1  Result: Too few digits!
Input:        -10  Result: Too few digits!
Input:       2002  Result: Not odd number of digits!
Input:      -2002  Result: Not odd number of digits!
Input:          0  Result: Too few digits! 

XPL0

<lang XPL0>include c:\cxpl\stdlib;

func Mid3Digits(I); \Return the middle three digits of I int I; int Len, Mid; char S(10); [ItoA(abs(I), S); Len:= StrLen(S); if Len<3 or (Len&1)=0 then return "Must be 3, 5, 7 or 9 digits"; Mid:= Len/2; S:= S + Mid - 1; S(2):= S(2) ! $80; \terminate string return S; \WARNING: very temporary ];

int Passing, Failing, X; [Passing:= [123, 12345, 1234567, 987654321, 10001, -10001, -123, -100, 100, -12345];

Failing:= [1, 2, -1, -10, 2002, -2002, 0];     \WARNING: nasty trick

for X:= 0 to 16 do

   [Text(0, "Middle three digits of ");  IntOut(0, Passing(X));
    Text(0, " returned: ");
    Text(0, Mid3Digits(Passing(X)));  CrLf(0);
   ];

]</lang>

Output:
Middle three digits of 123 returned: 123
Middle three digits of 12345 returned: 234
Middle three digits of 1234567 returned: 345
Middle three digits of 987654321 returned: 654
Middle three digits of 10001 returned: 000
Middle three digits of -10001 returned: 000
Middle three digits of -123 returned: 123
Middle three digits of -100 returned: 100
Middle three digits of 100 returned: 100
Middle three digits of -12345 returned: 234
Middle three digits of 1 returned: Must be 3, 5, 7 or 9 digits
Middle three digits of 2 returned: Must be 3, 5, 7 or 9 digits
Middle three digits of -1 returned: Must be 3, 5, 7 or 9 digits
Middle three digits of -10 returned: Must be 3, 5, 7 or 9 digits
Middle three digits of 2002 returned: Must be 3, 5, 7 or 9 digits
Middle three digits of -2002 returned: Must be 3, 5, 7 or 9 digits
Middle three digits of 0 returned: Must be 3, 5, 7 or 9 digits