"Break" a number

2

Origins

tl;dw (too lazy, didn't write): thought of it right before I fell asleep

Challenge

Breaking a number is defined as the following steps:

  • Take a number or a parseable data type as input in any allowed way.
  • Duplicate the first digit (64 -> 664)
  • Subtract 4 from the last digit (664 -> 660)
  • If the subtraction gets a negative last digit, move the negative sign (-) to the front of the number (73 -> 773 -> -771)
  • If the original number was negative, and the last digit becomes negative, remove all negative signs entirely. (-44441 -> 444443)
  • Output the number in any allowed way.

Here are a few test cases:

64 -> 660
73 -> -771
thisisnotanumber -> (handle the situation)
432188 -> 4432184
-83213 -> 883211 (two negative signs turn into a positive)
0 -> -4 (0 -> 00 -> 0-4 -> -04 -> -4)

Clarifications

Standard loopholes are disallowed.

By "parseable data type", I mean any data type (String, Float, etc) that can be converted into the number type your program/function uses (Integer, Number, etc).

Your answer can be a function or a program. In both cases, provide an explanation of the code.

If it is a function, give a usage of it.

Test cases (or online interpreter) would be a nice plus to your answer.

Preceding 0s (-04) aren't allowed.

Behavior should be exactly replicated from the test cases above.

InitializeSahib

Posted 2016-07-30T23:36:07.807

Reputation: 491

Question was closed 2016-07-31T11:49:49.353

Since it wasn't specified, I've assumed this is code golf and added the tag. If you intended a different winning criterion please edit to whatever you prefer. – trichoplax – 2016-07-30T23:48:51.230

@trichoplax i'd say falling gracefully is preferred, but hey, it's your code – InitializeSahib – 2016-07-30T23:52:41.383

3The trouble with "preferred" is that it isn't defined in the scoring, so no one will do it if it is not required, as it will adversely affect their score. – trichoplax – 2016-07-30T23:53:58.520

@trichoplax added to question – InitializeSahib – 2016-07-30T23:54:52.557

Could you define what "fail gracefully" means in this context? Should code return a particular string or give an error message? I usually post to the sandbox first to go through this clarification process before posting to main. I can recommend it for future challenges.

– trichoplax – 2016-07-31T00:03:29.967

@trichoplax defined – InitializeSahib – 2016-07-31T00:04:30.883

5It's still unclear to me. Also, I don't think that required behavior for invalid inputs really adds something to the challenge. – Dennis – 2016-07-31T00:07:13.227

8Note to self: will put in sandbox first. – InitializeSahib – 2016-07-31T00:08:12.587

Are languages that don't have number types allowed to participate? (Since you require input to be either a number type or something that can be converted to a number type?) – Martin Ender – 2016-07-31T08:11:34.633

Is -04 ok or does it have to be -4? – betseg – 2016-07-31T11:35:05.493

Answers

2

Batch, 105 bytes

@set/an=%1,n*=s=n^>^>31^|1
@set n=%n:~0,1%%n%
@cmd/cset/ad=n%%10,e=d-4,t=e^^^>^^^>31^^^|1,(n-d+e*t)*s*t

Alternatively the first line can be @set/as=%1^>^>31^|1,n=%1*s, also for 105 bytes. Explanation (without quoting metacharacters):

set /a n = %1               Get parameter
set /a s = n >> 31 | 1      Get sign of parameter
set /a n *= s               Get absolute value of parameter
set n=%n:~0,1%%n%           Duplicate the first digit
cmd /c                      Cause the final result to be printed
set /a d = n % 10           Get last digit
set /a e = d - 4            Calculate new last digit
set /a t = e >> 31 | 1      Get sign of new last digit
set /a e *= t               Get absolute value of new last digit
set /a (n - d + e) * s * t  Replace last digit and correct sign of result

Neil

Posted 2016-07-30T23:36:07.807

Reputation: 95 035

2

Ruby, 88 87 + 3 (-n flag) = 90 bytes

Regex approach that reads lines from STDIN. Probably better solved with Perl if it's just regex like this?

Returns a nonsense NoMethodError if the input is not a number, which costs 14 bytes. If there's no need to worry about invalid inputs like that (the spec implied it needed handling) then the first line of the code can be removed.

-2 bytes from @Dada

+(~/^-?\d+$/)
sub(/\d/){$&*2}
sub(/.$/){$&.to_i-4}
p sub(/(-)?(.+)-/){$1?$2:?-+$2}.to_i

Value Ink

Posted 2016-07-30T23:36:07.807

Reputation: 10 608

Nicely done. Your regex to check if the input is a number isn't quite right though, as it allows - anywhere, as well as inputs like ---. You'll probably want to use something like /^-?\d+$/ (which happens to be shorter by the way). – Dada – 2016-07-31T10:27:29.150

And indeed, the Perl solution is slightly shorter (66 bytes) : perl -pe '!/^-?\d+$/&¨s/\d/$&$&/;s/.$/$&-4/e;s/(-?)(.+)-/$1?$2:"-$2"/e;'. (which I won't post as it's your solution). – Dada – 2016-07-31T10:51:53.923

0

Pyth, 31 bytes

*i++hJja0QTPJa0K-eJ4T^_1x<K0<Q0

Naive implementation of the question.

Test suite.

Leaky Nun

Posted 2016-07-30T23:36:07.807

Reputation: 45 011

0

Python, 79 78 Bytes

lambda x:"+-"[(int(x)<0)!=(int(x[-1])-4<0)]+x[1]+x[1:-1]+str(int(x[-1])-4)[-1]

anonymous lambda function, does all of the four parts, then adds them together. Expects input as a string with explicit sign e.g. "+64", output is of the same form. Throws ValueError if the string cannot be converted to an int.

KarlKastor

Posted 2016-07-30T23:36:07.807

Reputation: 2 352

0

C, 191 bytes

f(char*n){if(!isdigit(*n)&!isdigit(n[1]))return 0;char*m;strcpy(m+1,n);*m=m[1];if(*n==45)m[1]=m[2];int a=strlen(n);if(m[a]<52)m[a]=100-m[a],m--,*m=45;else m[a]-=4;return atoi(m[1]^45?m:m+2);}

Ungolfed with explanations:

f(char*n){
    if(!isdigit(*n)&!isdigit(n[1])) /* if first two chars aren't digits
                                     * if it was only the first one, negative numbers wouldn't pass
                                     * if it was only the second one, 0 wouldn't pass */
        return 0;        // handling
    char*m;
    strcpy(m+1,n);        // copy leaving space for doubling the number
    *m=m[1];              // double the first digit or the minus sign
    if(*n==45)            // if negative
        m[1]=m[2];        // double the first digit
    int a=strlen(n);      /* length of the nunber
                           * it doesn't let me save 2 bytes, i dunno why. */
    if(m[a]<52)           // if the last digit is less than 4
        m[a]=100-m[a],    // subtract 4
        m--,              // leave space for minus sign
        *m=45;            // put minus sign
    else
        m[a]-=4;          // subtract 4 from the last digit
    return atoi(m[1]^45?m:m+2); /* if there are two minus signs, skip them,
                                 * turn the string into an integer, and return */
}

betseg

Posted 2016-07-30T23:36:07.807

Reputation: 8 493