How do I display the binary representation of a float or double? - language-agnostic

I'd like to display the binary (or hexadecimal) representation of a floating point number. I know how to convert by hand (using the method here), but I'm interested in seeing code samples that do the same.
Although I'm particularly interested in the C++ and Java solutions, I wonder if any languages make it particularly easy so I'm making this language agnostic. I'd love to see some solutions in other languages.
EDIT: I've gotten good coverage of C, C++, C#, and Java. Are there any alternative-language gurus out there who want to add to the list?

C/C++ is easy.
union ufloat {
float f;
unsigned u;
};
ufloat u1;
u1.f = 0.3f;
Then you just output u1.u.
Doubles just as easy.
union udouble {
double d;
unsigned long u;
}
because doubles are 64 bit.
Java is a bit easier: use Float.floatToRawIntBits() combined with Integer.toBinaryString() and Double.doubleToRawLongBits combined with Long.toBinaryString().

In C:
int fl = *(int*)&floatVar;
&floatVar would get the adress memory then (int*) would be a pointer to this adress memory, finally the * to get the value of the 4 bytes float in int.
Then you can printf the binary format or hex format.

Java: a google search finds this link on Sun's forums
specifically (I haven't tried this myself)
long binary = Double.doubleToLongBits(3.14159);
String strBinary = Long.toBinaryString(binary);

Apparently nobody cared to mention how trivial is to obtain hexadecimal exponent notation, so here it is:
#include <iostream>
#include <cstdio>
using namespace std;
int main()
{
// C++11 manipulator
cout << 23.0f << " : " << std::hexfloat << 23.0f << endl;
// C equivalent solution
printf("23.0 in hexadecimal is: %A\n", 23.0f);
}

In .NET (including C#), you have BitConverter that accepts many types, allowing access to the raw binary; to get the hex, ToString("x2") is the most common option (perhaps wrapped in a utility method):
byte[] raw = BitConverter.GetBytes(123.45);
StringBuilder sb = new StringBuilder(raw.Length * 2);
foreach (byte b in raw)
{
sb.Append(b.ToString("x2"));
}
Console.WriteLine(sb);
Oddly, base-64 has a 1-line conversion (Convert.ToBase64String), but base-16 takes more effort. Unless you reference Microsoft.VisualBasic, in which case:
long tmp = BitConverter.DoubleToInt64Bits(123.45);
string hex = Microsoft.VisualBasic.Conversion.Hex(tmp);

I did it this way:
/*
#(#)File: $RCSfile: dumpdblflt.c,v $
#(#)Version: $Revision: 1.1 $
#(#)Last changed: $Date: 2007/09/05 22:23:33 $
#(#)Purpose: Print C double and float data in bytes etc.
#(#)Author: J Leffler
#(#)Copyright: (C) JLSS 2007
#(#)Product: :PRODUCT:
*/
/*TABSTOP=4*/
#include <stdio.h>
#include "imageprt.h"
#ifndef lint
/* Prevent over-aggressive optimizers from eliminating ID string */
extern const char jlss_id_dumpdblflt_c[];
const char jlss_id_dumpdblflt_c[] = "#(#)$Id: dumpdblflt.c,v 1.1 2007/09/05 22:23:33 jleffler Exp $";
#endif /* lint */
union u_double
{
double dbl;
char data[sizeof(double)];
};
union u_float
{
float flt;
char data[sizeof(float)];
};
static void dump_float(union u_float f)
{
int exp;
long mant;
printf("32-bit float: sign: %d, ", (f.data[0] & 0x80) >> 7);
exp = ((f.data[0] & 0x7F) << 1) | ((f.data[1] & 0x80) >> 7);
printf("expt: %4d (unbiassed %5d), ", exp, exp - 127);
mant = ((((f.data[1] & 0x7F) << 8) | (f.data[2] & 0xFF)) << 8) | (f.data[3] & 0xFF);
printf("mant: %16ld (0x%06lX)\n", mant, mant);
}
static void dump_double(union u_double d)
{
int exp;
long long mant;
printf("64-bit float: sign: %d, ", (d.data[0] & 0x80) >> 7);
exp = ((d.data[0] & 0x7F) << 4) | ((d.data[1] & 0xF0) >> 4);
printf("expt: %4d (unbiassed %5d), ", exp, exp - 1023);
mant = ((((d.data[1] & 0x0F) << 8) | (d.data[2] & 0xFF)) << 8) |
(d.data[3] & 0xFF);
mant = (mant << 32) | ((((((d.data[4] & 0xFF) << 8) |
(d.data[5] & 0xFF)) << 8) | (d.data[6] & 0xFF)) << 8) |
(d.data[7] & 0xFF);
printf("mant: %16lld (0x%013llX)\n", mant, mant);
}
static void print_value(double v)
{
union u_double d;
union u_float f;
f.flt = v;
d.dbl = v;
printf("SPARC: float/double of %g\n", v);
image_print(stdout, 0, f.data, sizeof(f.data));
image_print(stdout, 0, d.data, sizeof(d.data));
dump_float(f);
dump_double(d);
}
int main(void)
{
print_value(+1.0);
print_value(+2.0);
print_value(+3.0);
print_value( 0.0);
print_value(-3.0);
print_value(+3.1415926535897932);
print_value(+1e126);
return(0);
}
Running on a SUN UltraSPARC, I got:
SPARC: float/double of 1
0x0000: 3F 80 00 00 ?...
0x0000: 3F F0 00 00 00 00 00 00 ?.......
32-bit float: sign: 0, expt: 127 (unbiassed 0), mant: 0 (0x000000)
64-bit float: sign: 0, expt: 1023 (unbiassed 0), mant: 0 (0x0000000000000)
SPARC: float/double of 2
0x0000: 40 00 00 00 #...
0x0000: 40 00 00 00 00 00 00 00 #.......
32-bit float: sign: 0, expt: 128 (unbiassed 1), mant: 0 (0x000000)
64-bit float: sign: 0, expt: 1024 (unbiassed 1), mant: 0 (0x0000000000000)
SPARC: float/double of 3
0x0000: 40 40 00 00 ##..
0x0000: 40 08 00 00 00 00 00 00 #.......
32-bit float: sign: 0, expt: 128 (unbiassed 1), mant: 4194304 (0x400000)
64-bit float: sign: 0, expt: 1024 (unbiassed 1), mant: 2251799813685248 (0x8000000000000)
SPARC: float/double of 0
0x0000: 00 00 00 00 ....
0x0000: 00 00 00 00 00 00 00 00 ........
32-bit float: sign: 0, expt: 0 (unbiassed -127), mant: 0 (0x000000)
64-bit float: sign: 0, expt: 0 (unbiassed -1023), mant: 0 (0x0000000000000)
SPARC: float/double of -3
0x0000: C0 40 00 00 .#..
0x0000: C0 08 00 00 00 00 00 00 ........
32-bit float: sign: 1, expt: 128 (unbiassed 1), mant: 4194304 (0x400000)
64-bit float: sign: 1, expt: 1024 (unbiassed 1), mant: 2251799813685248 (0x8000000000000)
SPARC: float/double of 3.14159
0x0000: 40 49 0F DB #I..
0x0000: 40 09 21 FB 54 44 2D 18 #.!.TD-.
32-bit float: sign: 0, expt: 128 (unbiassed 1), mant: 4788187 (0x490FDB)
64-bit float: sign: 0, expt: 1024 (unbiassed 1), mant: 2570638124657944 (0x921FB54442D18)
SPARC: float/double of 1e+126
0x0000: 7F 80 00 00 ....
0x0000: 5A 17 A2 EC C4 14 A0 3F Z......?
32-bit float: sign: 0, expt: 255 (unbiassed 128), mant: 0 (0x000000)
64-bit float: sign: 0, expt: 1441 (unbiassed 418), mant: -1005281217 (0xFFFFFFFFC414A03F)

Well both the Float and Double class (in Java) have a toHexString('float') method so pretty much this would do for hex conversion
Double.toHexString(42344);
Float.toHexString(42344);
Easy as pie!

I had to think about posting here for a while because this might inspire fellow coders to do evil things with C. I decided to post it anyway but just remember: do not write this kind of code to any serious application without proper documentation and even then think thrice.
With the disclaimer aside, here we go.
First write a function for printing for instance a long unsigned variable in binary format:
void printbin(unsigned long x, int n)
{
if (--n) printbin(x>>1, n);
putchar("01"[x&1]);
}
Unfortunately we can't directly use this function to print our float variable so we'll have to hack a little. The hack probably looks familiar to everyone who have read about Carmack's Inverse Square Root trick for Quake. The idea is set a value for our float variable and then get the same bit mask for our long integer variable. So we take the memory address of f, convert it to a long* value and use that pointer to get the bit mask of f as a long unsigned. If you were to print this value as long unsigned, the result would be a mess, but the bits are the same as in the original float value so it doesn't really matter.
int main(void)
{
long unsigned lu;
float f = -1.1f;
lu = *(long*)&f;
printbin(lu, 32);
printf("\n");
return 0;
}
If you think this syntax is awful, you're right.

In Haskell, there is no internal representation of floating points accessible. But you can do binary serialiazation from many formats, including Float and Double. The following solution is generic to any type that has instance of Data.Binary supports:
module BinarySerial where
import Data.Bits
import Data.Binary
import qualified Data.ByteString.Lazy as B
elemToBits :: (Bits a) => a -> [Bool]
elemToBits a = map (testBit a) [0..7]
listToBits :: (Bits a) => [a] -> [Bool]
listToBits a = reverse $ concat $ map elemToBits a
rawBits :: (Binary a) => a -> [Bool]
rawBits a = listToBits $ B.unpack $ encode a
Conversion can be done with rawBits:
rawBits (3.14::Float)
But, if you need to access the float value this way, you are probably doing something wrong. The real question might be How to access exponent and significand of a floating-point number? The answers are exponent and significand from Prelude:
significand 3.14
0.785
exponent 3.14
2

Python:
Code:
import struct
def float2bin(number, hexdecimal=False, single=False):
bytes = struct.pack('>f' if single else '>d', number)
func, length = (hex, 2) if hexdecimal else (bin, 8)
byte2bin = lambda byte: func(ord(byte))[2:].rjust(length, '0')
return ''.join(map(byte2bin, bytes))
Sample:
>>> float2bin(1.0)
'0011111111110000000000000000000000000000000000000000000000000000'
>>> float2bin(-1.0)
'1011111111110000000000000000000000000000000000000000000000000000'
>>> float2bin(1.0, True)
'3ff0000000000000'
>>> float2bin(1.0, True, True)
'3f800000'
>>> float2bin(-1.0, True)
'bff0000000000000'

You can easy convert float variable to int variable (or double to long) using such code in C#:
float f = ...;
unsafe
{
int i = *(int*)&f;
}

For future reference, C++ 2a introduce a new function template bit_cast that does the job.
template< class To, class From >
constexpr To bit_cast(const From& from) noexcept;
We can simply call,
float f = 3.14;
std::bit_cast<int>(f);
For more details, see https://en.cppreference.com/w/cpp/numeric/bit_cast

In C++ you can show the binary representation it in this way:
template <class T>
std::bitset<sizeof(T)*8> binary_representation(const T& f)
{
typedef unsigned long TempType;
assert(sizeof(T)<=sizeof(TempType));
return std::bitset<sizeof(T)*8>(*(reinterpret_cast<const TempType*>(&f)));
}
the limit here is due the fact that bitset longer parameter is an unsigned long,
so it works up to float, you can use something else than bitset and the extend
that assert.
BTW, cletus suggestion fails in the sense that you need an "unsingned long long" to cover a double, anyway you need something that shows the binary (1 or 0) representation.

Related

Why linking and calling a C function with variadic arguments in Rust causes random functions to be called? [duplicate]

This question already has an answer here:
Why does my C strlen() in Rust also count string slice inside print! macro after `s` variable?
(1 answer)
Closed last year.
I was playing with Rust FFI and I was trying to link printf C function, which has variadic arguments, with my Rust executable. After I ran the executable I witnessed some strange behavior.
This is my Rust code:
use cty::{c_char, c_int};
extern "C" {
fn printf(format: *const c_char, ...) -> c_int;
}
fn main() {
unsafe {
printf("One number: %d\n".as_ptr() as *const i8, 69);
printf("Two numbers: %d %d\n".as_ptr() as *const i8, 11, 12);
printf(
"Three numbers: %d %d %d\n".as_ptr() as *const i8,
30,
31,
32,
);
}
}
This is the output after running cargo run:
cargo run
Compiling c-bindings v0.1.0 (/home/costin/Rust/c-bindings)
Finished dev [unoptimized + debuginfo] target(s) in 0.20s
Running `target/debug/c-bindings`
One number: 1
Two numbers: 1 11376
Three numbers: 0 0 0
Two numbers: 11 12
Three numbers: 0 0 56
Three numbers: 30 31 32
I looks like the first printf calls the second and the third with random parameters, then the second printf calls the third one with random parameters because the expected output should have been:
One number: 1
Two numbers: 11 12
Three numbers: 30 31 32
Can anyone explain to me why is this strange behavior happening?
Rust strings are not null-terminated like printf expects. You'll need to either manually include \0 at the end of your format strings or use CString:
printf("One number: %d\n\0".as_ptr() as *const i8, 69);
use std::ffi::CString;
let s = CString::new("One number: %d\n").unwrap();
printf(s.as_ptr(), 69);

32-bit int struct bits don't seem to match up (nodejs)

I have a file that defines a set of tiles (used in an online game). The format for each tile is as follows:
x: 12 bits
y: 12 bits
tile: 8 bits
32 bits in total, so each tile can be expressed as a 32 bit integer.
More info about the file format can be found here:
http://wiki.minegoboom.com/index.php/LVL_Format
http://www.rarefied.org/subspace/lvlformat.html
The 4 byte structures are not broken along byte boundaries. As you can see x: and y: are both defined as 12 bits. ie. x is stored in 1.5 bytes, y is stored in 1.5 bytes and tile is stored in 1 byte.
Even though x and y use 12 bits their max value is 1023, so they could be expressed in 10 bits. This was down to the creator of the format. I guess they were just padding things out so they could use a 32-bit integer for each tile? Either way, for x and y we can ignore the final 2 bits.
I'm using a nodejs Buffer to read the file and I'm using the following code to read the values.
var n = tileBuffer.readUInt32LE(0);
var x = n & 0x03FF;
var y = (n >> 12) & 0x03FF;
var tile = (n >> 24) & 0x00ff;
This code works fine but when I read the bits themselves, in an attempt to understand binary better, I see something that confuses me.
Take, for example a int that expresses the following:
x: 1023
y: 1023
tile: 1
Creating the tiles in a map editor and reading the resulting file into a buffer returns <Buffer ff f3 3f 01>
When I convert each byte into a string of bits I get the following:
ff = 11111111
f3 = 11110011
3f = 00111111
01 = 00000001
11111111 11110011 00111111 00000001
I assume I should just take the first 12 bits as x but chop off the last 2 bits. Use the next 12 bits as y, chopping off 2 bits again, and the remaining 8 bits would be the tile.
x: 1111111111
y: 0011001111
tile: 00000001
The x is correct (1111111111 = 1023), the y is wrong (0011001111 = 207, not 1023), and tile is correct (00000001 = 1)
I'm confused and obviously missing something.
It makes more sense to look at it in this order: (this would be the binary representation of n)
00000001 00111111 11110011 11111111
On that order, you can easily do the masking and shifting visually.
The problem with what you did is that for example in 11111111 11110011, the bits of the second byte that belong to the first field are at the right (the lowest part of that byte), which in that order is discontinuous.
Also, masking with 0x03FF makes those first two fields have 10 bits, with two bits just disappearing. You can make them 12 bits by masking with 0x0FFF. As it is now, you effectively have two padding bits.

Get the IBAN number from an emv card

i have some issues with reading the IBAN number from the german CashCards (also known as Geldkarte).
I can communicate with my card, and i get some informations from it. but i don`t know which commandApdu i must send to the card, to get the IBAN number...
The application runs on Java 7 and i use the java.smartcardio api
Protocoll is T=1
my commandApdu to get the date looks like this:
byte[] commandBytes = new byte[]{0x00, (byte)0xa4, 0x04, 0x00, 0x07, (byte)0xa0, 0x00, 0x00, 0x00,0x04, 0x30, 0x60, 0x00};
the information i get is:
6F 32 84 07 A0 00 00 00 04 30 60 A5 27 50 07 4D 61 65 73 74 72 6F 87 01 03 9F 38 09 9F 33 02 9F 35 01 9F 40 01 5F 2D 04 64 65 65 6E BF 0C 05 9F 4D 02 19 0A
Can anyone tell me the correct apdu for getting the IBAN number?
i am sorry if i forgott some information needed, but this is my first question in this board :-)
Okay so the card has sent back this:
6F328407A0000000043060A52750074D61657374726F8701039F38099F33029F35019F40015F2D046465656EBF0C059F4D02190A
Which translates to:
6F File Control Information (FCI) Template
84 Dedicated File (DF) Name
A0000000043060
A5 File Control Information (FCI) Proprietary Template
50 Application Label
M a e s t r o
87 Application Priority Indicator
03
9F38 Processing Options Data Object List (PDOL)
9F33029F35019F4001
5F2D Language Preference
d e e n
BF0C File Control Information (FCI) Issuer Discretionary Data
9F4D Log Entry
190A
So now you've selected the application you'll want to send a series of 'Read Record' commands to it to get the data out of it like (Card number, expiry date, card holder name, IBAN (if it's in there, haven't seen it before)). The structure of the 'Read Record' command can be found in EMV Book 3 however here's some rough psuedocode as to what your Read Record loop should look like. Off the top of my head I usually set NUM_SFIS to 5 and NUM_RECORDS to 16 as there's not usually anything past these points.
for (int sfiNum = 1; sfiNum <= NUM_SFIS; sfiNum++)
{
for (int rec = 1; rec <= NUM_RECORDS; rec++)
{
byte[] response = tag.transceive(new byte[]{0x00,(byte)0xB2 (byte)rec, (byte)((byte)(sfiNum << 3) | 4), 0x00});
}
}
i solved my problem after a long time this way:
At first send a command to the card, to select the aid (application identifier):
private static byte[] aidWithPossibleIban = new byte[] { 0x00, (byte) 0xa4,
0x04, 0x00, 0x09, (byte) 0xa0, 0x00, 0x00, 0x00, 0x59, 0x45, 0x43,
0x01, 0x00, 0x00 };
then i hat to raise the security-level:
private static byte[] cmdRaiseSecurityLevel = new byte[] { 0x00, 0x22,
(byte) 0xf3, 0x02 };
last thing to do was to read the record:
private static byte[] readSelectedRecord = new byte[] { 0x00, (byte) 0xb2,
0x01, (byte) 0xa4, 0x00 };
regards
Andreas
I would like to add, the IBAN returning from the card is not straightforward.
The IBAN returned is that of the main Bank, and then the account number from the card holder in other record. Therefore one must come out with the right IBAN through code as the check digit has to be calculated as seen here
Since in records we find Country Code (DE), Bankleitzahl BLZ (8 Digits) and Account Number (10 digits), Check Digit can be calculated through
public string ReturnIBAN(string lkz, string blz, string kntnr, bool groupedReturn = true)
{
string bban = string.Empty;
lkz = lkz.ToUpper();
switch (lkz)
{
case "AT":
{
bban = blz.PadLeft(5, '0') + kntnr.PadLeft(11, '0');
}
break;
case "DE":
{
bban = blz.PadLeft(8, '0') + kntnr.PadLeft(10, '0');
}
break;
case "CH":
{
bban = blz.PadLeft(5, '0') + kntnr.PadLeft(12, '0');
}
break;
}
string sum = bban + lkz.Aggregate("", (current, c) => current + (c - 55).ToString()) + "00";
var d = decimal.Parse(sum);
var checksum = 98 - (d % 97);
string iban = lkz + checksum.ToString().PadLeft(2, '0') + bban;
return groupedReturn ? iban.Select((c, i) => (i % 4 == 3) ? c + " " : c + "").Aggregate("", (current, c) => current + c) : iban;
}
Source (In German): here

Code Golf: Four is magic

Locked. This question and its answers are locked because the question is off-topic but has historical significance. It is not currently accepting new answers or interactions.
The puzzle
A little puzzle I heard while I was in high school went something like this...
The questioner would ask me to give him a number;
On hearing the number, the questioner would do some sort of transformation on it repeatedly (for example, he might say ten is three) until eventually arriving at the number 4 (at which point he would finish with four is magic).
Any number seems to be transformable into four eventually, no matter what.
The goal was to try to figure out the transformation function and then be able to reliably proctor this puzzle yourself.
The solution
The transformation function at any step was to
Take the number in question,
Count the number of letters in its English word representation, ignoring a hyphen or spaces or "and" (e.g., "ten" has 3 letters in it, "thirty-four" has 10 letters in it, "one hundred forty-three" has 20 letters in it).
Return that number of letters.
For all of the numbers I have ever cared to test, this converges to 4. Since "four" also has four letters in it, there would be an infinite loop here; instead it is merely referred to as magic by convention to end the sequence.
The challenge
Your challenge is to create a piece of code that will read a number from the user and then print lines showing the transformation function being repeatedly applied until "four is magic" is reached.
Specifically:
Solutions must be complete programs in and of themselves. They cannot merely be functions which take in a number-- factor in the input.
Input must be read from standard input. (Piping from "echo" or using input redirection is fine since that also goes from stdin)
The input should be in numeric form.
For every application of the transformation function, a line should be printed: a is b., where a and b are numeric forms of the numbers in the transformation.
Full stops (periods) ARE required!
The last line should naturally say, 4 is magic..
The code should produce correct output for all numbers from 0 to 99.
Examples:
> 4
4 is magic.
> 12
12 is 6.
6 is 3.
3 is 5.
5 is 4.
4 is magic.
> 42
42 is 8.
8 is 5.
5 is 4.
4 is magic.
> 0
0 is 4.
4 is magic.
> 99
99 is 10.
10 is 3.
3 is 5.
5 is 4.
4 is magic.
The winner is the shortest submission by source code character count which is also correct.
BONUS
You may also try to write a version of the code which prints out the ENGLISH NAMES for the numbers with each application of the transformation function. The original input is still numeric, but the output lines should have the word form of the number.
(Double bonus for drawing shapes with your code)
(EDIT) Some clarifications:
I do want the word to appear on both sides in all applicable cases, e.g. Nine is four. Four is magic.
I don't care about capitalization, though. And I don't care how you separate the word tokens, though they should be separated: ninety-nine is okay, ninety nine is okay, ninetynine is not okay.
I'm considering these a separate category for bonus competition with regard to the challenge, so if you go for this, don't worry about your code being longer than the numeric version.
Feel free to submit one solution for each version.
Perl, about 147 char
Loosely based on Platinum Azure's solution:
chop
($_.=
<>);#
u="433
5443554
366 887
798 866
555 766
"=~ /\d
/gx ;#4
sub r{4
-$_ ?$_
<20 ?$u
[$_ ]:(
$'? $u[
$'] :0)
+$u[18+$&]:magic}print"
$_ is ",$_=r(),'.'while
/\d
/x;
444
GolfScript - 101 96 93 92 91 90 94 86 bytes
90 → 94: Fixed output for multiples of 10.
94 → 86: Restructured code. Using base 100 to remove non-printable characters.
86 → 85: Shorter cast to string.
{n+~."+#,#6$DWOXB79Bd")base`1/10/~{~2${~1$+}%(;+~}%++=" is "\".
"1$4$4-}do;;;"magic."
Common Lisp 157 Chars
New more conforming version, now reading form standard input and ignoring spaces and hyphens:
(labels((g (x)(if(= x 4)(princ"4 is magic.")(let((n(length(remove-if(lambda(x)(find x" -"))(format nil"~r"x)))))(format t"~a is ~a.~%"x n)(g n)))))(g(read)))
In human-readable form:
(labels ((g (x)
(if (= x 4)
(princ "4 is magic.")
(let ((n (length (remove-if (lambda(x) (find x " -"))
(format nil "~r" x)))))
(format t"~a is ~a.~%" x n)
(g n)))))
(g (read)))
And some test runs:
>24
24 is 10.
10 is 3.
3 is 5.
5 is 4.
4 is magic.
>23152436
23152436 is 64.
64 is 9.
9 is 4.
4 is magic.
And the bonus version, at 165 chars:
(labels((g(x)(if(= x 4)(princ"four is magic.")(let*((f(format nil"~r"x))(n(length(remove-if(lambda(x)(find x" -"))f))))(format t"~a is ~r.~%"f n)(g n)))))(g(read)))
Giving
>24
twenty-four is ten.
ten is three.
three is five.
five is four.
four is magic.
>234235
two hundred thirty-four thousand two hundred thirty-five is forty-eight.
forty-eight is ten.
ten is three.
three is five.
five is four.
four is magic.
Python 2.x, 144 150 154 166 chars
This separates the number into tens and ones and sum them up. The undesirable property of the pseudo-ternary operator a and b or c that c is returned if b is 0 is being abused here.
n=input()
x=0x4d2d0f47815890bd2
while n-4:p=n<20and x/10**n%10or 44378/4**(n/10-2)%4+x/10**(n%10)%10+4;print n,"is %d."%p;n=p
print"4 is magic."
The previous naive version (150 chars). Just encode all lengths as an integer.
n=input()
while n-4:p=3+int('1yrof7i9b1lsi207bozyzg2m7sclycst0zsczde5oks6zt8pedmnup5omwfx56b29',36)/10**n%10;print n,"is %d."%p;n=p
print"4 is magic."
C - with number words
445 431 427 421 399 386 371 359* 356 354† 348 347 characters
That's it. I don't think I can make this any shorter.
All newlines are for readability and can be removed:
i;P(x){char*p=",one,two,three,four,five,six,sM,eight,nine,tL,elM,twelve,NP,4P,
fifP,6P,7P,8O,9P,twLQ,NQ,forQ,fifQ,6Q,7Q,8y,9Q,en,evL,thir,eL,tO,ty, is ,.\n,
4RmagicS,zero,";while(x--)if(*++p-44&&!x++)*p>95|*p<48?putchar(*p),++i:P(*p-48);
}main(c){for(scanf("%d",&c);c+(i=-4);P(34),P(c=i),P(35))P(c?c>19?P(c/10+18),
(c%=10)&&putchar(45):0,c:37);P(36);}
Below, it is somewhat unminified, but still pretty hard to read. See below for a more readable version.
i;
P(x){
char*p=",one,two,three,four,five,six,sM,eight,nine,tL,elM,twelve,NP,4P,fifP,6P,7P,8O,9P,twLQ,NQ,forQ,fifQ,6Q,7Q,8y,9Q,en,evL,thir,eL,tO,ty, is ,.\n,4RmagicS,zero,";
while(x--)
if(*++p-44&&!x++)
*p>95|*p<48?putchar(*p),++i:P(*p-48);
}
main(c){
for(scanf("%d",&c);c+(i=-4);P(34),P(c=i),P(35))
P(c?
c>19?
P(c/10+18),
(c%=10)&&
putchar(45)
:0,
c
:37);
P(36);
}
Expanded and commented:
int count; /* type int is assumed in the minified version */
void print(int index){ /* the minified version assumes a return type of int, but it's ignored */
/* see explanation of this string after code */
char *word =
/* 1 - 9 */
",one,two,three,four,five,six,sM,eight,nine,"
/* 10 - 19 */
"tL,elM,twelve,NP,4P,fifP,6P,7P,8O,9P,"
/* 20 - 90, by tens */
"twLQ,NQ,forQ,fifQ,6Q,7Q,8y,9Q,"
/* lookup table */
"en,evL,thir,eL,tO,ty, is ,.\n,4RmagicS,zero,";
while(index >= 0){
if(*word == ',')
index--;
else if(index == 0) /* we found the right word */
if(*word >= '0' && *word < 'a') /* a compression marker */
print(*word - '0'/*convert to a number*/);
else{
putchar(*word); /* write the letter to the output */
++count;
}
++word;
}
}
int main(int argc, char **argv){ /* see note about this after code */
scanf("%d", &argc); /* parse user input to an integer */
while(argc != 4){
count = 0;
if(argc == 0)
print(37/*index of "zero"*/);
else{
if(argc > 19){
print(argc / 10/*high digit*/ + 20/*offset of "twenty"*/ - 2/*20 / 10*/);
argc %= 10; /* get low digit */
if(argc != 0) /* we need a hyphen before the low digit */
putchar('-');
}
print(argc/* if 0, then nothing is printed or counted */);
}
argc = count;
print(34/*" is "*/);
print(argc); /* print count as word */
print(35/*".\n"*/);
}
print(36/*"four is magic.\n"*/);
}
About the encoded string near the beginning
The names of the numbers are compressed using a very simple scheme. Frequently used substrings are replaced with one-character indices into the name array. A "lookup table" of extra name entries is added to the end for substrings not used in their entirety in the first set. Lookups are recursive: entries can refer to other entries.
For instance, the compressed name for 11 is elM. The print() function outputs the characters e and l (lower-case 'L', not number '1') verbatim, but then it finds the M, so it calls itself with the index of the 29th entry (ASCII 'M' - ASCII '0') into the lookup table. This string is evL, so it outputs e and v, then calls itself again with the index of the 28th entry in the lookup table, which is en, and is output verbatim. This is useful because en is also used in eL for een (used after eight in eighteen), which is used in tO for teen (used for every other -teen name).
This scheme results in a fairly significant compression of the number names, while requiring only a small amount of code to decompress.
The commas at the beginning and end of the string account for the simplistic way that substrings are found within this string. Adding two characters here saves more characters later.
About the abuse of main()
argv is ignored (and therefore not declared in the compressed version), argc's value is ignored, but the storage is reused to hold the current number. This just saves me from having to declare an extra variable.
About the lack of #include
Some will complain that omitting #include <stdio.h> is cheating. It is not at all. The given is a completely legal C program that will compile correctly on any C compiler I know of (albeit with warnings). Lacking protoypes for the stdio functions, the compiler will assume that they are cdecl functions returning int, and will trust that you know what arguments to pass. The return values are ignored in this program, anyway, and they are all cdecl ("C" calling convention) functions, and we do indeed know what arguments to pass.
Output
Output is as expected:
0
zero is four.
four is magic.
1
one is three.
three is five.
five is four.
four is magic.
4
four is magic.
20
twenty is six.
six is three.
three is five.
five is four.
four is magic.
21
twenty-one is nine.
nine is four.
four is magic.
* The previous version missed the mark on two parts of the spec: it didn't handle zero, and it took input on the command line instead of stdin. Handling zeros added characters, but using stdin instead of command line args, as well as a couple of other optimzations saved the same number of characters, resulting in a wash.
† The requirements have been changed to make clear that the number word should be printed on both sides of " is ". This new version meets that requirement, and implements a couple more optimizations to (more than) account for the extra size necessary.
J, 107 112 characters
'4 is magic.',~}:('.',~":#{.,' is ',":#{:)"1]2&{.\.
(]{&(#.100 4$,#:3 u:ucp'䌵䐵吶梇禈榛ꪛ멩鮪鮺墊馊꥘誙誩墊馊ꥺ겻곋榛ꪛ멩鮪鮺'))^:a:
(Newline for readability only)
Usage and output:
'4 is magic.',~}:('.',~":#{.,' is ',":#{:)"1]2&{.\.(]{&(#.100 4$,#:3 u:ucp'䌵䐵吶梇禈榛ꪛ멩鮪鮺墊馊꥘誙誩墊馊ꥺ겻곋榛ꪛ멩鮪鮺'))^:a:12
12 is 6.
6 is 3.
3 is 5.
5 is 4.
4 is magic.
T-SQL, 413 451 499 chars
CREATE FUNCTION d(#N int) RETURNS int AS BEGIN
Declare #l char(50), #s char(50)
Select #l='0066555766',#s='03354435543668877987'
if #N<20 return 0+substring(#s,#N+1,1) return 0+substring(#l,(#N/10)+1,1) + 0+(substring(#s,#N%10+1,1))END
GO
CREATE proc M(#x int) as BEGIN
WITH r(p,n)AS(SELECT p=#x,n=dbo.d(#x) UNION ALL SELECT p=n,n=dbo.d(n) FROM r where n<>4)Select p,'is',n,'.' from r print '4 is magic.'END
(Not that I'm seriously suggesting you'd do this... really I just wanted to write a CTE)
To use:
M 95
Returns
p n
----------- ---- -----------
95 is 10.
10 is 3.
3 is 5.
5 is 4.
4 is magic.
Java (with boilerplate), 308 290 286 282 280 characters
class A{public static void main(String[]a){int i=4,j=0;for(;;)System.out.printf("%d is %s.%n",i=i==4?new java.util.Scanner(System.in).nextInt():j,i!=4?j="43354435543668877988699;::9;;:699;::9;;:588:998::9588:998::9588:998::97::<;;:<<;699;::9;;:699;::9;;:".charAt(i)-48:"magic");}}
I'm sure Groovy would get rid of much of that.
Explanation and formatting (all comments, newlines and leading/trailing whitespace removed in count):
Reasonably straight forward, but
//boilerplate
class A{
public static void main(String[]a){
//i is current/left number, j right/next number. i=4 signals to start
//by reading input
int i=4,j=0;
for(;;)
//print in the form "<left> is <right>."
System.out.printf(
"%d is %s.%n",
i=i==4?
//<left>: if i is 4 <left> will be a new starting number
new java.util.Scanner(System.in).nextInt():
//otherwise it's the next val
j,
i!=4?
//use string to map number to its length (:;< come after 9 in ASCII)
//48 is value of '0'. store in j for next iteration
j="43354435543668877988699;::9;;:699;::9;;:588:998::9588:998::9588:998::97::<;;:<<;699;::9;;:699;::9;;:".charAt(i)-48:
//i==4 is special case for right; print "magic"
"magic");
}
}
Edit: No longer use hex, this is less keystrokes
Windows PowerShell: 152 153 184 bytes
based on the previous solution, with more influence from other solutions
$o="03354435543668877988"
for($input|sv b;($a=$b)-4){if(!($b=$o[$a])){$b=$o[$a%10]-48+"66555766"[($a-$a%10)/10-2]}$b-=48-4*!$a
"$a is $b."}'4 is magic.'
C, 158 characters
main(n,c){char*d="03354435543668877988";for(scanf("%d",&n);n-4;n=c)printf("%d is %d.\n",n,c=n?n<19?d[n]-48:d[n%10]-"_,**+++)**"[n/10]:4);puts("4 is magic.");}
(originally based on Vlad's Python code, borrowed a trick from Tom Sirgedas' C++ solution to squeeze out a few more characters)
expanded version:
main(n, c) {
char *d = "03354435543668877988";
for (scanf("%d",&n); n-4; n = c)
printf("%d is %d.\n", n, c = n ? n<19 ? d[n]-48 : d[n%10] - "_,**+++)**"[n/10] : 4);
puts("4 is magic.");
}
Python, 129 133 137 148 chars
As a warm-up, here is my first version (improves couple of chars over previous best Python).
PS. After a few redactions now it is about twenty char's shorter:
n=input()
while n-4:p=(922148248>>n/10*3&7)+(632179416>>n%10*3&7)+(737280>>n&1)+4*(n<1);print n,'is %d.'%p;n=p
print'4 is magic.'
C#: 210 Characters.
Squished:
using C=System.Console;class B{static void Main(){int
x=0,y=int.Parse(C.ReadLine());while(x!=4)C.Write((x=y)+" is {0}.\n",x==4?"magic":""+(y=x==0?4:"03354435543668877988"[x<20?x:x%10]+"0066555766"[x/10]-96));}}
Expanded:
using C=System.Console;
class B
{
static void Main()
{
int x=0,y=int.Parse(C.ReadLine());
while(x!=4)
C.Write((x=y)+" is {0}.\n",
x==4?
"magic":
""+(y= x==0?
4:
"03354435543668877988"[x<20?x:x%10]+
"0066555766"[x/10]-96)
);
}
}
Tricks this approach uses:
Create a lookup table for number name lengths based on digits that appear in the number.
Use character array lookup on a string, and char arithmetic instead of a numeric array.
Use class name aliasing to short Console. to C.
Use the conditional (ternary) operator (?:) instead of if/else.
Use the \n with Write escape code instead of WriteLine
Use the fact that C# has a defined order of evaluation to allow assignments inside the Write function call
Use the assignment expressions to eliminate extra statements, and thus extra braces
Perl: 148 characters
(Perl: 233 181 212 206 200 199 198 185 179 149 148 characters)
Moved exceptions hash into unit array. This resulted in my being able to cut a lot of characters :-)
mobrule pointed out a nasty bug. Quick fix adds 31 characters, ouch!
Refactored for zero special case, mild golfing done as well.
Direct list access for single use rather than storing to array? Hell yes!
SO MUCH REFACTORING for just ONE bloody character. This, truly, is the life of a golfer. :-(
Oops, easy whitespace fix. 198 now.
Refactored some redundant code.
Last return keyword in r is unnecessary, shaved some more off.
Massive refactoring per comments; unfortunately I could only get it to 149 because I had to fix a bug that was present in both my earlier code and the commenters' versions.
Trying bareword "magic".
Let's get this ball rolling with a modest attempt in Perl.
#u=split'','4335443554366887798866555766';$_=<>;chop;print"$_ is ".($_=$_==4?0:$_<20?$u[$_]:($u[$_/10+18]+($_%10&&$u[$_%10]))or magic).".
"while$_
Tricks:
Too many!
JavaScript 1.8 (SpiderMonkey) - 153 Chars
l='4335443554366887798866555766'.split('')
for(b=readline();(a=+b)-4;print(a,'is '+b+'.'))b=a<20?l[a]:+l[18+a/10|0]+(a%10&&+l[a%10])
print('4 is magic.')
Usage: echo 42 | js golf.js
Output:
42 is 8.
8 is 5.
5 is 4.
4 is magic.
With bonus - 364 chars
l='zero one two three four five six seven eight nine ten eleven twelve thirteen fourteen fifteen sixteen seventeen eighteen nineteen twenty thirty fourty fifty sixty seventy eighty ninety'.split(' ')
z=function(a)a<20?l[a]:l[18+a/10|0]+(a%10?' '+l[a%10]:'')
for(b=+readline();(a=b)-4;print(z(a),'is '+z(b)+'.'))b=z(a).replace(' ','').length
print('four is magic.')
Output:
ninety nine is ten.
ten is three.
three is five.
five is four.
four is magic.
Haskell, 224 270 characters
o="43354435543668877988"
x!i=read[x!!i]
n x|x<20=o!x|0<1="0066555766"!div x 10+o!mod x 10
f x=zipWith(\a b->a++" is "++b++".")l(tail l)where l=map show(takeWhile(/=4)$iterate n x)++["4","magic"]
main=readLn>>=mapM putStrLn.f
And little more readable -
ones = [4,3,3,5,4,4,3,5,5,4,3,6,6,8,8,7,7,9,8,8]
tens = [0,0,6,6,5,5,5,7,6,6]
n x = if x < 20 then ones !! x else (tens !! div x 10) + (ones !! mod x 10)
f x = zipWith (\a b -> a ++ " is " ++ b ++ ".") l (tail l)
where l = map show (takeWhile (/=4) (iterate n x)) ++ ["4", "magic"]
main = readLn >>= mapM putStrLn . f
C++ Stdio version, minified: 196 characters
#include <cstdio>
#define P;printf(
char*o="43354435543668877988";main(int p){scanf("%d",&p)P"%d",p);while(p!=4){p=p<20?o[p]-48:"0366555966"[p/10]-96+o[p%10]P" is %d.\n%d",p,p);}P" is magic.\n");}
C++ Iostreams version, minified: 195 characters
#include <iostream>
#define O;std::cout<<
char*o="43354435543668877988";main(int p){std::cin>>p;O p;while(p!=4){p=p<20?o[p]-48:"0366555966"[p/10]-96+o[p%10]O" is "<<p<<".\n"<<p;}O" is magic.\n";}
Original, un-minified: 344 characters
#include <cstdio>
int ones[] = { 4, 3, 3, 5, 4, 4, 3, 5, 5, 4, 3, 6, 6, 8, 8, 7, 7, 9, 8, 8 };
int tens[] = { 0, 3, 6, 6, 5, 5, 5, 9, 6, 6 };
int n(int n) {
return n<20 ? ones[n] : tens[n/10] + ones[n%10];
}
int main(int p) {
scanf("%d", &p);
while(p!=4) {
int q = n(p);
printf("%i is %i\n", p, q);
p = q;
}
printf("%i is magic\n", p);
}
Delphi: 329 characters
Single Line Version:
program P;{$APPTYPE CONSOLE}uses SysUtils;const S=65;A='EDDFEEDFFEDGGIIHHJII';B='DGGFFFJGG';function Z(X:Byte):Byte;begin if X<20 then Z:=Ord(A[X+1])-S else Z:=(Ord(B[X DIV 10])-S)+Z(X MOD 10)end;var X,Y:Byte;begin Write('> ');ReadLn(X);repeat Y:=Z(X);WriteLn(Format('%d is %d.',[X,Y]));X:=Y;until X=4;WriteLn('4 is magic.');end.
Formated:
program P;
{$APPTYPE CONSOLE}
uses
SysUtils;
const
S = 65;
A = 'EDDFEEDFFEDGGIIHHJII';
B = 'DGGFFFJGG';
function Z(X:Byte):Byte;
begin
if X<20
then Z := Ord(A[X+1])-S
else Z := (Ord(B[X DIV 10])-S) + Z(X MOD 10);
end;
var
X,Y: Byte;
begin
Write('> ');
ReadLn(X);
repeat
Y:=Z(X);
WriteLn(Format('%d is %d.' , [X,Y]));
X:=Y;
until X=4;
WriteLn('4 is magic.');
end.
Probably room for some more squeezing... :-P
C# 314 286 283 274 289 273 252 chars.
Squished:
252
Normal:
using C = System.Console;
class P
{
static void Main()
{
var x = "4335443554366877798866555766";
int m, o, v = int.Parse(C.ReadLine());
do {
C.Write("{0} is {1}.\n", o = v, v == 4 ? (object)"magic" : v = v < 20 ? x[v] - 48 : x[17 + v / 10] - 96 + ((m = v % 10) > 0 ? x[m] : 48));
} while (o != 4);
C.ReadLine();
}
}
Edit Dykam: Did quite some carefull insertions and changes:
Changed the l.ToString() into a cast to object of the string "magic".
Created a temporary variable o, so I could move the break outside the for loop, that is, resulting in a do-while.
Inlined the o assignment, aswell the v assignment, continueing in inserting the calculation of l in the function arguments altogether, removing the need for l. Also inlined the assignment of m.
Removed a space in int[] x, int[]x is legit too.
Tried to transform the array into a string transformation, but the using System.Linq was too much to make this an improvement.
Edit 2 Dykam
Changed the int array to a char array/string, added proper arithmics to correct this.
Lua, 176 Characters
o={[0]=4,3,3,5,4,4,3,5,5,4,3,6,6,8,8,7,7,9,8,8}t={3,6,6,5,5,5,7,6,6}n=0+io.read()while n~=4 do a=o[n]or o[n%10]+t[(n-n%10)/10]print(n.." is "..a..".")n=a end print"4 is magic."
or
o={[0]=4,3,3,5,4,4
,3,5,5,4,3,6,6,8,8
,7,7,9,8,8}t={3,6,
6,5,5,5,7,6,6}n=
0+io.read()while
n ~= 4 do a= o[n
]or o[n%10]+t[(n
-n%10)/10]print(
n.." is "..a.."." )n=a
end print"4 is magic."
C - without number words
180 175* 172 167 characters
All newlines are for readability and can be removed:
i;V(x){return"\3#,#6$:WOXB79B"[x/2]/(x%2?1:10)%10;}main(c){for(scanf("%d",&c);
c-4;)i=c,printf("%d is %d.\n",i,c=c?c>19?V(c/10+19)+V(c%10):V(c):4);puts(
"4 is magic.");}
Slightly unminified:
i;
V(x){return"\3#,#6$:WOXB79B"[x/2]/(x%2?1:10)%10;}
main(c){
for(scanf("%d",&c);c-4;)
i=c,
printf("%d is %d.\n",i,c=c?c>19?V(c/10+19)+V(c%10):V(c):4);
puts("4 is magic.");
}
* The previous version missed the mark on two parts of the spec: it didn't handle zero, and it took input on the command line instead of stdin. Handling zero added characters, but using stdin instead of command line args saved even more, resulting in a net savings.
perl, 123 122 characters
Just realized that there is no requirement to output to STDOUT, so output to STDERR instead and knock off another character.
#u='0335443554366887798866555766'=~/./g;$_+=<>;warn"$_ is ",$_=$_-4?$_<20?$u[$_]||4:$u[chop]+$u[$_+18]:magic,".\n"until/g/
And, a version that returns spelled out numbers:
279 278 276 280 characters
#p=(Thir,Four,Fif,Six,Seven,Eigh,Nine);#n=("",One,Two,Three,Four,Five,#p[3..6],Ten,Eleven,Twelve,map$_.teen,#p);s/u//for#m=map$_.ty,Twen,#p;$n[8].=t;sub n{$n=shift;$n?$n<20?$n[$n]:"$m[$n/10-2] $n[$n%10]":Zero}$p+=<>;warnt$m=n($p)," is ",$_=$p-4?n$p=()=$m=~/\w/g:magic,".\n"until/c/
While that meets the spec, it is not 100% well formatted. It returns an extra space after numbers ending in zero. The spec does say:
"I don't care how you separate the word tokens, though they should be separated"
That's kind of weaselly though.
A more correct version at
282 281 279 283 characters
#p=(Thir,Four,Fif,Six,Seven,Eigh,Nine);#n=("\x8",One,Two,Three,Four,Five,#p[3..6],Ten,Eleven,Twelve,map$_.teen,#p);s/u//for#m=map$_.ty,Twen,#p;$n[8].=t;sub n{$n=shift;$n?$n<20?$n[$n]:"$m[$n/10-2]-$n[$n%10]":Zero}$p+=<>;warn$m=n($p)," is ",$_=$p-4?n$p=()=$m=~/\w/g:magic,".\n"until/c/
Python:
#!/usr/bin/env python
# Number of letters in each part, we don't count spaces
Decades = ( 0, 3, 6, 6, 6, 5, 5, 7, 6, 6, 0 )
Smalls = ( 0, 3, 3, 5, 4, 4, 3, 5, 5, 4 )
Teens = ( 6, 6, 8, 8, 7, 7, 9, 8, 8 )
def Count(n):
if n > 10 and n < 20: return Teens[n-11]
return Smalls[n % 10 ] + Decades [ n / 10 ]
N = input()
while N-4:
Cnt = Count(N)
print "%d is %d" % ( N, Cnt)
N = Cnt
print "4 is magic"
C++, 171 characters (#include omitted)
void main(){char x,y,*a="03354435543668877988";scanf("%d",&x);for(;x-4;x=y)y=x?x<19?a[x]-48:"_466555766"[x/10]+a[x%10]-96:4,printf("%d is %d.\n",x,y);puts("4 is magic.");}
Ruby, 164 characters
n=gets.to_i;s="03354435543668877987";if n==0;puts"0 is 4.";else;puts"#{n} is #{n=(n<20)?s[n]-48:"0066555766"[n/10]-48+s[n%10]-48}." until n==4;end;puts"4 is magic."
decoded:
n = gets.to_i
s = "03354435543668877987"
if n == 0
puts "0 is 4."
else
puts "#{n} is #{n = (n < 20) ? s[n] - 48 : "0066555766"[n / 10] - 48 + s[n % 10] - 48}." until n == 4
end
puts "4 is magic."
Lua 185 190 199
added periods, added io.read, removed ()'s on last print
n=io.read();while(n~=4)do m=('43354435543668877988699;::9;;:699;::9;;:588:998::9588:998::9588:998::97::<;;:<<;699;::9;;:699;::9;;:'):sub(n+1):byte()-48;print(n,' is ',m,'.')n=m;end print'4 is magic.'
with line breaks
n=io.read()
while (n~=4) do
m=('43354435543668877988699;::9;;:699;::9;;:588:998::9588:998::9588:998::97::<;;:<<;699;::9;;:699;::9;;:'):sub(n+1):byte()-48;
print(n,' is ',m,'.')
n=m;
end
print'4 is magic.'
PhP Code
function get_num_name($num){
switch($num){
case 1:return 'one';
case 2:return 'two';
case 3:return 'three';
case 4:return 'four';
case 5:return 'five';
case 6:return 'six';
case 7:return 'seven';
case 8:return 'eight';
case 9:return 'nine';
}
}
function num_to_words($number, $real_name, $decimal_digit, $decimal_name){
$res = '';
$real = 0;
$decimal = 0;
if($number == 0)
return 'Zero'.(($real_name == '')?'':' '.$real_name);
if($number >= 0){
$real = floor($number);
$decimal = number_format($number - $real, $decimal_digit, '.', ',');
}else{
$real = ceil($number) * (-1);
$number = abs($number);
$decimal = number_format($number - $real, $decimal_digit, '.', ',');
}
$decimal = substr($decimal, strpos($decimal, '.') +1);
$unit_name[1] = 'thousand';
$unit_name[2] = 'million';
$unit_name[3] = 'billion';
$unit_name[4] = 'trillion';
$packet = array();
$number = strrev($real);
$packet = str_split($number,3);
for($i=0;$i<count($packet);$i++){
$tmp = strrev($packet[$i]);
$unit = $unit_name[$i];
if((int)$tmp == 0)
continue;
$tmp_res = '';
if(strlen($tmp) >= 2){
$tmp_proc = substr($tmp,-2);
switch($tmp_proc){
case '10':
$tmp_res = 'ten';
break;
case '11':
$tmp_res = 'eleven';
break;
case '12':
$tmp_res = 'twelve';
break;
case '13':
$tmp_res = 'thirteen';
break;
case '15':
$tmp_res = 'fifteen';
break;
case '20':
$tmp_res = 'twenty';
break;
case '30':
$tmp_res = 'thirty';
break;
case '40':
$tmp_res = 'forty';
break;
case '50':
$tmp_res = 'fifty';
break;
case '70':
$tmp_res = 'seventy';
break;
case '80':
$tmp_res = 'eighty';
break;
default:
$tmp_begin = substr($tmp_proc,0,1);
$tmp_end = substr($tmp_proc,1,1);
if($tmp_begin == '1')
$tmp_res = get_num_name($tmp_end).'teen';
elseif($tmp_begin == '0')
$tmp_res = get_num_name($tmp_end);
elseif($tmp_end == '0')
$tmp_res = get_num_name($tmp_begin).'ty';
else{
if($tmp_begin == '2')
$tmp_res = 'twenty';
elseif($tmp_begin == '3')
$tmp_res = 'thirty';
elseif($tmp_begin == '4')
$tmp_res = 'forty';
elseif($tmp_begin == '5')
$tmp_res = 'fifty';
elseif($tmp_begin == '6')
$tmp_res = 'sixty';
elseif($tmp_begin == '7')
$tmp_res = 'seventy';
elseif($tmp_begin == '8')
$tmp_res = 'eighty';
elseif($tmp_begin == '9')
$tmp_res = 'ninety';
$tmp_res = $tmp_res.' '.get_num_name($tmp_end);
}
break;
}
if(strlen($tmp) == 3){
$tmp_begin = substr($tmp,0,1);
$space = '';
if(substr($tmp_res,0,1) != ' ' && $tmp_res != '')
$space = ' ';
if($tmp_begin != 0){
if($tmp_begin != '0'){
if($tmp_res != '')
$tmp_res = 'and'.$space.$tmp_res;
}
$tmp_res = get_num_name($tmp_begin).' hundred'.$space.$tmp_res;
}
}
}else
$tmp_res = get_num_name($tmp);
$space = '';
if(substr($res,0,1) != ' ' && $res != '')
$space = ' ';
$res = $tmp_res.' '.$unit.$space.$res;
}
$space = '';
if(substr($res,-1) != ' ' && $res != '')
$space = ' ';
if($res)
$res .= $space.$real_name.(($real > 1 && $real_name != '')?'s':'');
if($decimal > 0)
$res .= ' '.num_to_words($decimal, '', 0, '').' '.$decimal_name.(($decimal > 1 && $decimal_name != '')?'s':'');
return ucfirst($res);
}
//////////// testing ////////////////
$str2num = 12;
while($str2num!=4){
$str = num_to_words($str2num, '', 0, '');
$str2num = strlen($str)-1;
echo $str . '=' . $str2num .'<br/>';
if ($str2num == 4)
echo 'four is magic';
}
////// Results /////////
Twelve =6
Six =3
Three =5
Five =4
four is magic
Perl - 130 chars
5.12.1 (130 chars) 121 123 132 136 140
# 1 2 3 4 5 6 7 8 9 100 11 12 13 14
#23456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123
#u='4335443554366887798866555766'=~/./g;$_=pop;say"$_ is ",$_=$_-4?$_<20?$u[$_]:$u[$_/10+18]+(($_%=10)&&$u[$_]):magic,"."until/\D/
5.10.1 (134 chars) 125 127 136 140 144
# 1 2 3 4 5 6 7 8 9 100 11 12 13 14
#23456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 1234
#u='4335443554366887798866555766'=~/./g;$_=pop;print"$_ is ",$_=$_-4?$_<20?$u[$_]:$u[$_/10+18]+(($_%=10)&&$u[$_]):magic,".\n"until/\D/
Change History:
20100714:2223 - reverted change at the attention of mobrule, but ($_%10&&$u[$_%10]) → (($_%=10)&&$u[$_]), which is the same # of chars, but I did it in case someone might see a way to improve it
20100714:0041 - split//,'...' → '...'=~/./g
20100714:0025 - ($_%10&&$u[$_%10]) → $u[$_%10]
20100713:2340 - while$_ → until/\D/ + removed unnecessary parentheses
20100713:xxxx - $=<>;chop; → $_=pop; - courtesy to mobrule
Note: I was tired of improving others' answers in comments, so now I'm being greedy and can just add my changes here :) This is a split off from Platinum Azure's answer - credit in part to Hobbs, mobrule, and Platinum Azure.
Shameless Perl with Number Words (329 characters)
Adapted fairly directly from P Daddy's C code, with some tweaks to p() to make it do the same thing using Perl primitives instead of C ones, and a mostly-rewritten mainloop. See his for an explanation. Newlines are all optional.
#t=(qw(zero one two three four five six sM eight nine
tL elM twelve NP 4P fifP 6P 7P 8O 9P twLQ NQ forQ fifQ
6Q 7Q 8y 9Q en evL thir eL tO ty 4SmagicT)," is ",".\n");
sub p{local$_=$t[pop];1while s/[0-Z]/$t[-48+ord$&]/e;
print;length}$_=<>;chop;while($_-4){
$_=($_>19?(p($_/10+18),$_&&print("-"),$_%=10)[0]:0)+p$_;
p 35;p$_;p 36}p 34
Side note: it's too bad that perl print just returns true/false; if it returned a count it would save me 7 strokes.
Ruby, 141 chars:
n=gets.to_i;m="4335443554366887798866555766";loop{s=n;n=n>20?m[18+n/10]+m[n%10]-96: m[n]-48;puts"#{s} is #{n==s ? 'magic': n}.";n==s &&break}
while(true)
{
string a;
ReadLine(a)
WriteLine(4);
}

Code Golf: Seven Segments

Locked. This question and its answers are locked because the question is off-topic but has historical significance. It is not currently accepting new answers or interactions.
The challenge
The shortest code by character count to generate seven segment display representation of a given hex number.
Input
Input is made out of digits [0-9] and hex characters in both lower and upper case [a-fA-F] only. There is no need to handle special cases.
Output
Output will be the seven segment representation of the input, using those ASCII faces:
_ _ _ _ _ _ _ _ _ _ _ _
| | | _| _| |_| |_ |_ | |_| |_| |_| |_ | _| |_ |_
|_| | |_ _| | _| |_| | |_| _| | | |_| |_ |_| |_ |
Restrictions
The use of the following is forbidden: eval, exec, system, figlet, toilet and external libraries.
Test cases:
Input:
deadbeef
Output:
_ _ _ _ _
_||_ |_| _||_ |_ |_ |_
|_||_ | ||_||_||_ |_ |
Input:
4F790D59
Output:
_ _ _ _ _ _
|_||_ ||_|| | _||_ |_|
|| | _||_||_| _| _|
Code count includes input/output (i.e full program).
Perl, 134 characters
All linebreaks may be removed.
#s=unpack"C*",~"P\xdbLI\xc3a`[\#AB\xe0t\xc8df";
$_=<>;for$s(6,3,0){print map$s[hex$&]&1<<$_+$s?$_%2?"_":"|":" ",
0..2while/./g;print$/}
Explanation
#s stores the bits for each segment. The entries are in order from 0 to F (thanks to hex()) and the bits map to segments in this order:
6 7 x
3 4 5
0 1 2
with 0 being the LSB. (Bit 6 is unused). The values are stored packed in the string bit-inverted so there are a lot more printable characters; the ~ operator flips the bits and unpack gives me numbers (perl's bitwise operators are much clumsier when it comes to strings).
With the data in hand I read the input and proceed to loop over it three times; the only difference between the three loops is the bitmask required. For each character of input three characters of output are printed. The character to be printed is
$s[ hex $& ] & (1 << ($_ + $s) )
? ($_ % 2 ? "_" : "|" )
: " "
where #s is the lookup table, $s is the shift in effect depending on the row, and $_ is whether we're printing the 1st, 2nd, or 3rd character in the row. If the right bit in the lookup table entry is false it prints a space; otherwise it prints a "|" on the sides or a "_" in the middle.
C89 (181 characters; args)
char*q,a=3;p(l){putchar(*q?"|#]u&rzc~vn:X=ZJ"[*q-(*q&64?55:48
)&15]+1>>l&1?"|_||_|_"[l]:32:10);}main(r,v)char**v;{for(;a--
;p())for(q=v[1];*q;++q)for(r=3;r--;)p(a-2?5-r-a*3:r-1?7:6);}
C89 (192 characters; stdin)
char*q,b[9],gets(char*),a=3;p(l){putchar(*q?"|#]u&rzc~vn:X=ZJ"[*
q-(*q&64?55:48)&15]+1>>l&1?"|_||_|_"[l]:32:10);}main(r){for(gets
(b);a--;p())for(q=b;*q;++q)for(r=3;r--;)p(a-2?5-r-a*3:r-1?7:6);}
Explanation:
char*q,b[9],gets(char*),a=3;
p(l){
putchar(*q?
/*
* Each element of the magic string is decremented so 0x7F is
* '~' (0x7E). Each bit before the decrement represents
* a segment (thus "8" is 0x7F (0x7E), i.e. all 7 bits on).
* Bit 7 is always cleared so p(7) always prints a space.
*/
"|#]u&rzc~vn:X=ZJ"
[*q-(*q&64?55:48)&15]+1 /* d[ascii2hex(*q)] + 1 */
>>l&1 /* Is bit 'l' set? */
?"|_||_|_"[l] /* Yes; choose _ or | by position. */
:32 /* No; enter a space. */
:10); /* End of line. */
}
main(r){
for(gets(b);a--;p()) /* Grab input and loop through each of 3 lines (a = 2, 1, 0). */
for(q=b;*q;++q) /* Iterate across input. */
for(r=3;r--;) /* For each of three characters across... */
p(a-2?5-r-a*3:r-1?7:6); /* Print the segment, mapping position to the bit. */
}
COM Executable: 102 bytes
Assemble the following using A86 (this is the original, larger version):
dd 0801E8Ah,0BD80C380h,03B50154h,0D789D58Ah,0B20082BEh,077F33B03h,0C048A29h,0149F0420h
dd 020AD431h,088C402C4h,01468BC1h,0F8C1E0D3h,046220Fh,0AA036E8Dh,0DD75CAFEh,04609ED83h
dd 0C583D1EBh,0D0AB809h,075CDFEABh,0AA24B0C3h,021CD09B4h,05F0000C3h,020B7EBh,8EFB7C00h
dd 07C3EF75Fh,0BF7CF9E4h,0B6DE5FA2h
dw 0F47Ch
db 0DFh
Edit:
The DosBox issue is probably the way the program assumes register values at start-up. Anyhow, here's the modified source that assembles to 102 bytes and should work with DosBox:
mov bp,d1
mov ch,3
mov dx,ds ; if you want to use dos box, put "mov dx,08000h" here instead, it might fix the problem
mov di,dx
l4: mov si,082h
l3: mov bl,3
cmp byte ptr [si],0dh
je l5
mov cl,[si]
cmp cl,40h
jle l2
add cl,9
l2: and cl,0fh
l1: mov ax,word ptr [bp+1]
shl ax,cl
sar ax,15
and al,byte ptr [bp]
add bp,3
stosb
dec bl
jnz l1
sub bp,9
inc si
jmp l3
l5: add bp,9
mov ax,0d0ah
stosw
dec ch
jnz l4
mov al,'$'
stosb
mov ah,9
int 21h
d1: ret
dw 0
db '_'
dw 01011011111101011xb
db ' '
dw 0
db '|'
dw 01000111011111011xb
db '_'
dw 00011111011110111xb
db '|'
dw 01111100111100100xb
db '|'
dw 01010001010111111xb
db '_'
dw 01011011011011110xb
db '|'
dw 01101111111110100xb
Thanks to ephemient for a couple of tweaks!
x86 (146 bytes; args)
Inspired by Jonas Gulle over in the Code Golf: The wave. Usually I'd be writing a 32-bit Linux ELF, but a 16-bit DOS COM is much smaller (shorter instructions, zero overhead).
46 instructions and 24 non-executed words. (They do stand out quite obviously at the end there, don't they?) Nothing tricky like reusing code as data; it probably wouldn't save more than 10 bytes anyhow.
C:\>od -xAn ss.com
c930 82be ac00 0d3c 3e74 403c 027e 0904
0f24 0198 bbc8 0162 c301 0eb4 078a 0424
0474 7cb0 02eb 20b0 10cd 078a 0224 0474
5fb0 02eb 20b0 10cd 078a 0124 0474 7cb0
02eb 20b0 10cd bdeb f980 7420 b014 cd0d
b010 cd0a 6610 c381 0010 0000 c180 eb10
c3a1 0002 0202 0200 0202 0202 0002 0002
0202 0105 0303 0607 0106 0707 0607 0304
0606 0107 0306 0301 0107 0307 0705 0706
0406
C:\>ss deadbeef
_ _ _ _ _
_||_ |_| _||_ |_ |_ |_
|_||_ | ||_||_||_ |_ |
This just goes letter-by-letter printing the first line, then the second line, etc. using 3 bytes to store the 9 bits of data for each character. Obviously there's room left for enhancement… (This is my first time using NASM syntax; I'm more accustomed to gas but I couldn't convince it to output a raw binary.)
org 0x100
; initialize registers
xor cl,cl
; reset ds:[si] to start of arguments
start:
mov si,0x82
; load one character of arguments
read:
lodsb
cmp al,0xd
je next
; transform [0-9A-Fa-f] to [\x00-\x0f]
cmp al,0x40
jle skipa
add al,0x9
skipa:
and al,0xf
; load font definition
cbw
add ax,cx
mov bx,letters
add bx,ax
mov ah,0xe
; print first char
mov al,[bx]
and al,0x4
jz s1
mov al,0x7c
jmp short w1
s1:
mov al,0x20
w1:
int 0x10
; print second char
mov al,[bx]
and al,0x2
jz s2
mov al,0x5f
jmp short w2
s2:
mov al,0x20
w2:
int 0x10
; print third char
mov al,[bx]
and al,0x1
jz s3
mov al,0x7c
jmp short w3
s3:
mov al,0x20
w3:
int 0x10
; next character
jmp short read
; print newline
next:
cmp cl,0x20
je end
mov al,0xd
int 0x10
mov al,0xa
int 0x10
add ebx,0x10
add cl,0x10
jmp short start
end:
ret
letters:
db 2,0,2,2,0,2,2,2,2,2,2,0,2,0,2,2
db 5,1,3,3,7,6,6,1,7,7,7,6,4,3,6,6
db 7,1,6,3,1,3,7,1,7,3,5,7,6,7,6,4
Man... can't beat the perl. Here's some py3k at 163 chars.
i=input()
[print(''.join(' | _ _|| | ||_ |_|'[(7&(d>>l))*3:][:3]for d
in[255&0xb4b61fa637bdbbbf89b7b3399b9e09af>>int(x,16)*8 for x in i]))for
l in[6,3,0]]
Explanation. First here's what it looked like completely unoptimized:
# segment positions, easily understandable as octal. first digit is top row
# last digit is bottom row. high bit is first column, low bit last.
a=[0o257, 0o011, 0o236, 0o233,
0o071, 0o263, 0o267, 0o211,
0o277, 0o273, 0o275, 0o067,
0o246, 0o037, 0o266, 0o264]
# and the corresponding segments:
# 421 421 421 421 421 421 421 421
b=[' ', ' |', ' _ ', ' _|', '| ', '| |', '|_ ', '|_|']
# function to look for the proper segment for a decoded digit:
def lookup(digit, line):
return b[ 7& (digit>>(6-line*3))]
#function to encode an ascii hex string into coded form suitible for
#above function
def code(i):
return [a[int(x,16)] for x in i]
def fmt(i):
return '\n'.join(''.join(lookup(d,l) for d in code(i)) for l in [0,1,2])
i = input()
print(fmt(i))
Then i go about finding ways to pack the data. First I can transform a into a big, long integer, last element first, 8 bits at a time. That produces, in octal: 0o2645541764615736673577046675463463347404657. written in hex, that's 0xb4b61fa637bdbbbf89b7b3399b9e09af, 90 chars shorter than the list of octals. To use it you have to rewrite code, of course. That looks like
def code_a_8(i):
return [255&a_8>>int(x,16)*8 for x in i]
b can be concatenated, ''.join(b) is 26 chars, including the quotes. the lookup function must also change to support this.
def lookup_b_cat(d, l):
return b_cat[(7&(d>>6-l*3))*3:][:3]
Next I just eliminate all unneeded syntax by folding functions and constants into the expression, and that's pretty much it.
It's possible to tighten up the printing a bit, too. Instead of joining the lines, just print them immediately. this results in a modified fmt():
def fmt_print(i):
[print(''.join(lookup(d,l) for d in code(i))) for l in [0,1,2]]
Well, it's hard to beat a specialized language like Perl. However, here's Python version at 160 bytes:
i=input().lower()
for x in[' #_ 14bd# ','| 1237d#_ 017c#| 56bcef','| 134579#_ 147af#| 2cef']: print(' '.join(''.join(y[j in y]for y in x.split('#'))for j in i))
The ungolfed version:
input_ = input().lower()
for magic in [' #_ 14bd# ',
'| 1237d#_ 017c#| 56bcef',
'| 134579#_ 147af#| 2cef',
]:
# We have three lines, so x iterates over 3 magic strings.
print(' '.join(
# This is the cycle iterating over digits.
''.join(
# For each line and digit we need to print several
# letters. To do this, we break a magic string into
# 3 chunks. A chunk usually contains digits that
# *don't* have an element there.
chunk[digit in chunk]
# For example, lower right chunk y="| 2cef". For digits
# 2, c, e, f, there should be " ", for all others there
# should be "|". So for digits 2, c, e, f, `j in y` returns
# False and indexes y[0], for other digits it indexes y[1].
for chunk in magic.split('#'))
for digit in input_))
Golfscript - 116 chars
$ echo -n deadbeef | ./golfscript.rb led.gs
_ _ _ _ _
_||_ |_| _||_ |_ |_ |_
|_||_ | ||_||_||_ |_ |
Make sure to save without an extra newline on the end or the input string will be printed at the end.
{32:^|}%:
{^' _':$#'14bd'{?~!=}:&~^}%n
{:x' |':|\'1237d'&$x'017c'&|x'56bcef'&}%n
{:x|\'134579'&$x'147af'&|x'2cef'&}%
How it works
Notice that more segments are turned on than off for the range 0-F. List the exceptions (digits that have the segment turned off) for each segment.
#Python version of the algorithm above
s=raw_input().lower()
J=''.join()
print J(' '+'_ '[c in'14bd']+' 'for c in s)
print J('| '[c in'1237d']+'_ '[c in'017c']+'| '[c in'56bcef']for c in s)
print J('| '[c in'134579']+'_ '[c in'147af']+'| '[c in'2cef']for c in s)
C (170 characters)
i,j;main(c,s){char**r=s,*p=*++r;for(;i<3;)j--?putchar(!p[-1]?p=*r,++i,j=0,10:
"##3#3133X=W.<X/`^_G0?:0#"[i*8+c/2]-33>>c%2*3+j&1?"|_"[j&1]:32):(j=3,c=*p++&31,
c-=c>6?10:1);}
This takes the input string as a command-line argument. Conversion to use stdin would be one more character:
i,j;main(c){char s[99],*p=s;for(gets(s+1);i<3;)j--?putchar(!*p?p=s,++i,j=0,10:
"##3#3133X=W.<X/`^_G0?:0#"[i*8+c/2]-33>>c%2*3+j&1?"|_"[j&1]:32):(j=3,c=*++p&31,
c-=c>6?10:1);}
The stdin version can accept up to 98 input characters. Of course, any more than floor(terminalWidth / 3) will cause confusing line wrap.
The output for each character is treated like a 3x3 grid, where the cells in each row are the segments. A segment is either "on" or "off". If a segment is "on", either a '|' or a '_' is output, depending on position. If it's off, a space is output. The character array is an array of bits that determine whether each segment is on or off. More about that after the code:
i,j; /* Loop variables. As globals, they'll be initialized to zero. */
main(c,s){
/* The signature for main is
*
* main(int argc, char **argv)
*
* Rather than add more characters for properly declaring the parameters,
* I'm leaving them without type specifiers, allowing them to default to
* int. On almost all modern platforms, a pointer is the same size as
* an int, so we can get away with the next line, which assigns the int
* value s to the char** variable r.
*/
char**r=s,*p=*++r;
/* After coercing the int s to a char** r, offset it by 1 to get the
* value of argv[1], which is the command-line argument. (argv[0] would
* be the name of the executable.)
*/
for(;i<3;) /* loop until we're done with 3 lines */
j--?
/* j is our horizontal loop variable. If we haven't finished a
* character, then ... */
putchar( /* ...we will output something */
!p[-1]? /* if the previous char was a terminating null ... */
p=*r,++i,j=0,10
/* ... reset for the next row. We need to:
*
* - reinitialize p to the start of the input
* - increment our vertical loop variable, i
* - set j to zero, since we're finished with this
* "character" (real characters take 3 iterations of
* the j loop to finish, but we need to short-circuit
* for end-of-string, since we need to output only one
* character, the newline)
* - finally, send 10 to putchar to output the newline. */
:"##3#3133X=W.<X/`^_G0?:0#"[i*8+c/2]-33>>c%2*3+j&1?
/* If we haven't reached the terminating null, then
* check whether the current segment should be "on" or
* "off". This bit of voodoo is explained after the
* code. */
"|_"[j&1]:32
/* if the segment is on, output either '|' or '_',
* depending on position (value of j), otherwise,
* output a space (ASCII 32) */
)/* end of putchar call */
:(j=3,c=*p++&31,c-=c>6?10:1);
/* this is the else condition for j--? above. If j was zero,
* then we need to reset for the next character:
*
* - set j to 3, since there are three cells across in the grid
* - increment p to the next input character with p++
* - convert the next character to a value in the range 0–15.
* The characters we're interested in, 0–9, A–F, and a–f, are
* unique in the bottom four bits, except the upper- and
* lowercase letters, which is what we want. So after anding
* with 15, the digits will be in the range 16–25, and the
* letters will be in the range 1–6. So we subtract 10 if
* it's above 6, or 1 otherwise. Therefore, input letters
* 'A'–'F', or 'a'–'f' map to values of c between 0 and 5,
* and input numbers '0'–'9' map to values of c between
* 6 and 15. The fact that this is not the same as the
* characters' actual hex values is not important, and I've
* simply rearranged the data array to match this order.
*/
}
The character array describes the character grids. Each character in the array describes one horizontal row of the output grid for two input characters. Each cell in the grid is represented by one bit, where 1 means that segment is "on" (so output a '|' or a '_', depending on position), and 0 means that segment is "off".
It takes three characters in the array to describe the entire grid for two input characters. The lowest three bits of each character in the array, bits 0-2, describe one row for the even input character of the two. The next three bits, bits 3-5, describe one row for the odd input character of the two. Bits 6 and 7 are unused. This arrangement, with an offset of +33, allows every character in the array to be printable, without escape codes or non-ASCII characters.
I toyed with several different encodings, including putting the bits for all 7 segments of an input character into one character in the array, but found this one to be the overall shortest. While this scheme requires 24 characters in the array to represent the segments of only 16 input characters, other encodings either required using non-ASCII characters (which unsurprisingly caused problems when I used this in my Morse Code golf answer), a lot of escape codes, and/or complex decoding code. The decoding code for this scheme is surprisingly simple, although it does take full advantage of C's operator precedence to avoid having to add any parentheses.
Let's break it into tiny steps to understand it.
"##3#3133X=W.<X/`^_G0?:0#"
This is the encoded array. Let's grab the appropriate character to decode.
[i*8
The first 8 characters describe the top row of segments, the next 8 describe the middle row of segments, and the last 8 describe the bottom row of segments.
+c/2]
Remember that, by this point, c contains a value from 0 to 15, which corresponds to an input of ABCDEF0123456789, and that the array encodes two input characters per encoded character. So the first character in the array, '#', holds the bits for the top row of 'A' and of 'B', the second character, also '#', encodes the top row of 'C' and 'D', and so on.
-33
The encoding results in several values that are under 32, which would require escape codes. This offset brings every encoded character into the range of printable, unescaped characters.
>>
The right shift operator has lower precedence than arithmetic operators, so this shift is done to the character after subtracting the offset.
c%2*3
c%2 evaluates to zero for even numbers, and to one for odd numbers, so we'll shift right by three for odd characters, to get at bits 3–5, and not shift at all for even characters, providing access to bits 0–2. While I'd prefer to use c&1 for even/odd check, and that is what I use everywhere else, the & operator has too low precedence to use here without adding parentheses. The % operator has just the right precedence.
+j
Shift by an additional j bits to get at the correct bit for the current output position.
&1
The bitwise and operator has lower precedence than both the arithmetic operators and the shift operators, so this will test whether bit zero is set after shifting has brought the relevant bit into bit zero.
?
If bit zero is set ...
"|_"
... output one of these characters, chosen by ...
[j&1]
... whether our horizontal loop variable is even or odd.
:32
Otherwise (bit zero is not set), output 32 (space character).
I don't think I can trim this down much more, if any, and certainly not enough to beat hobbs's perl entry.
Ruby: 175
d="3yy0nxcoypnk4185nbr3k9ddjlhe".to_i 36
s=gets.chomp
o=''
for i in 0..2
s.each_char{|c|q=d>>c.to_i(16)*3
"|_|".each_char{|z|o<<(q&1>0?z:' ')
q>>=1}}
d>>=48
o<<"\n"
end
puts o
And when a bit more readable...
d="3yy0nxcoypnk4185nbr3k9ddjlhe".to_i 36
s=gets.chomp
o=''
for i in 0..2
s.each_char { |c|
q = d >> c.to_i(16) * 3
"|_|".each_char { |z|
o << (q & 1 > 0 ? z : ' ')
q >>= 1
}
}
d >>= 48
o << "\n"
end
puts o
My first code golf. 279 non-whitespace characters, 433 including spaces. I'm sure it could be shorter in Python.
Python
import sys
w = sys.stdout.write
i = raw_input()
d = [111,9,94,91,57,115,119,73,127,123,125,55,102,31,118,116]
p = [' _ ','|','_','|','|','_','|']
j = 0
for r in range(3):
for c in i.lower():
for n in range(3 if r else 1):
s = p[j+n]
if (1<<6-j-n) & d[ord(c)-(ord('0') if c.isdigit() else ord('a')+6)]:
w(s)
else:
w(' '*len(s))
j += n+1
w('\n')
BrainF***, 920 906 885 868 863 860 858 chars for digital clock
I started on this on the (now closed) digital clock code golf, so : is supported as well. Todo: handle lowercase.
-[>+<-----]->----[>,]<[<]>>[[->]<+[-<+]->]<+>-[>]+++[[<]>>[[>]>[>]+[<]<[<]+[>]>[
>]+[-<+]->[[>]>[>]<+[<]<[<]>+[>]+[-<+]->-]->]<[<]>+[-[>]+[-<+]+<[<]>[[>]+[-<+]->
+<[<]>-]>+]+[-->]+[->]-[>-<-----]>+++>-->->----<<<[>>+++>+++++>-[+++<]>]-<+[>]-[
<]>>>+[-<<+[->+]<<-[-[++>->>[>]>>+++++>>+++++>>>>>+++++>>>+++++++>>>>>>+++++>>>+
++++>>+[<+]<[<]<]>[-<++>>>[>]<--->+>+>->++++++>+>-->>>>>>>+++>-->-->>+>+>-->->->
>+++++>+[<++++]<[<]]<]>[-<+>>>[>]<--->++++++>+>-->+>-->+++++>>>>>>>+++>->-->>-->
->>->+>>-->+[<++++]<[<]]<+>-[[>]>[>]<[-]<[<]<[<]>-]>[>]>[>]+<-[-[-[-[-[-[-[-[-[[
<]<<.>...>>[>]<-]>[<+[<]<<.>.<.>.>>[>]<->]<]>[<+[<]<..>>[>]<->]<]>[<+[<]<<<<.>>>
.>>[>]<->]<]>[<+[<]<....>>[>]<->]<]>[<+[<]<<.<.>>..>>[>]<->]<]>[<+[<]<..<.>.>>[>
]<->]<]>[<+[<]<.<<.>.>.>>[>]<->]<]>[<+[<]<<.<.>.>.>>[>]<->]<]>[<+[<]<.<<.>>..>>[
>]<->]<<[[-]<]-[<]>>>+]++++++++++.[>]<[[-]<]+[-<+]-[>]<-]
$ echo 01:23456789DEADBEEF | beef clock.b
_ _ _ _ _ _ _ _ _ _ _ _ _
| | | . _| _| |_| |_ |_ | |_| |_| _| |_ |_| _| |_ |_ |_ |_
|_| | . |_ _| | _| |_| | |_| _| |_| |_ | | |_| |_| |_ |_ |
This depends heavily on the platform being 8-bit.
Python, 188 total chars
I haven't looked too much at the other solutions, but I'm sure there is still a lot of room for improvement.
n=int(raw_input(),16)
O=[""]*3
while n:O=["".join(" |_"[(m>>n%16*3+i&1)*(i%2+1)]for i in[2,1,0])+o
for o,m in zip(O,[0x482092490482,0xd9cdff3b76cd,0x9bef5f3d978f])];n>>=4
print"\n".join(O)
F#, 294 chars
I did nothing clever, but still get a respectable score.
let rec G s=for r in[" _ _ _ _ _ _ _ _ _ _ _ _ ";"| | | _| _||_||_ |_ ||_||_||_||_ | _||_ |_ ";"|_| ||_ _| | _||_| ||_| _|| ||_||_ |_||_ | "]do Seq.iter(printf"%s"<<S r)s;printfn""
and S a h=a.Substring(3*(int h-if h<'A'then 48 elif h<'a'then 55 else 87),3)
With whitespace for clarity:
let rec G s=
for r in[" _ _ _ _ _ _ _ _ _ _ _ _ ";
"| | | _| _||_||_ |_ ||_||_||_||_ | _||_ |_ ";
"|_| ||_ _| | _||_| ||_| _|| ||_||_ |_||_ | "] do
Seq.iter (printf "%s" << S r) s;
printfn""
and S a h=
a.Substring(3*(int h - if h<'A'
then 48
elif h<'a'
then 55
else 87),3)
Sample:
G("abcdefFEDCBA9876543210")
Output:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
|_||_ | _||_ |_ |_ |_ _|| |_ |_||_||_| ||_ |_ |_| _| _| || |
| ||_||_ |_||_ | | |_ |_||_ |_|| | _||_| ||_| _| | _||_ ||_|
C++, 286 bytes
Hehe, everybody has come up with a more concise way to represent the data.
Anyway, so that it wouldn't be a complete waste of time (input from command line):
#include<cstdio>
#define P(x)putchar(x);
int main(int,char**v){int i,j,d[]={0,6947821,0,7209841,7734140,1180575,8257861,
3933037,1442811};char*p,c[]="|_|";for(++v;*v;++v){for(i=0;i<9;i+=3){for(p=*v;*p;
++p){for(j=0;j<3;++j)P(1<<((*p>96?*p-32:*p)-48)&d[i+j]?c[j]:32)P(32)}P(10)}P(10)
}}
And unobfuscated:
#include <cstdio>
void out(const char* s)
{
int i, j;
const char* c = "|_|";
unsigned d[9] = {0, 6947821, 0, 7209841, 7734140, 1180575, 8257861, 3933037, 1442811};
for (i = 0; i < 9; i += 3) {
for (const char* p = s; *p; ++p) {
for (j = 0; j != 3; ++j)
putchar(1 << ((*p > 96 ? *p - 32 : *p) - '0') & d[j + i] ? c[j] : ' ');
putchar(' ');
}
putchar('\n');
}
}
int main(int, char** argv)
{
for (++argv;*argv;) {
out(*argv++);
putchar('\n');
}
}
The magic numbers refer to which characters have a _ or a | at a particular position. E.g if 0, 3, 5, and 'A' all have a | somewhere, the number would be 1 << n('0') | 1 << n('3') | 1 << n('5') | 1 << n('A') - where n(x) means x - '0'. This assumes at least 32-bit integers, as there is a small gap between '9' and 'A' in ASCII chart.
Both codes were edited recently: use one-dimensional array instead of two-dimensional (d), own non-error-proof "toupper" instead of including cctype, moved everything into main, another way of looping over command line arguments, more condensed variable declarations, magic values instead of char constants and a few other minor changes.
Java 1.5 - 272 characters with unnecessary whitespace removed
Much shorter than earlier version, using some ideas from JRL. Could be made shorter by using command line arguments, but that goes against the spec.
class D{public static void main(String[]a){char[]q=new java.util.Scanner
(System.in).nextLine().toCharArray();int j=0,k;for(;j<9;j+=3){for(int c:
q){for(k=j;k<j+3;k++){System.out.print(("{H=mNgwI\177o_v3|7\027".charAt(
"0123456789abcdef".indexOf(c|32))&"\0\1\0\2\4\10\20 #".charAt(k))>0?
" _ |_||_|".charAt(k):32);}}System.out.println();}}}
Mine isn't short, but it was fun to do:
~ dlamblin$ ./7seg 31337aAbcdeF
_ _ _ _ _ _ _ _ _
_| | _| _| ||_||_||_ | _||_ |_
_| | _| _| || || ||_||_ |_||_ |
#include <stdio.h>
#define P(x) fputs(x,stdout)
#define Z "\33[3D\33[B"
#define a " " Z
#define s " _ " Z
#define d " |" Z
#define f " _|" Z
#define g "| " Z
#define h "| |" Z
#define j "|_ " Z
#define k "|_|" Z
int main(int argc, char** argv){
char m=0,n,*b[]={s h k,a d d,s f j,s f f,a k d,s j f,s j k,s d d,s k k,s k d,
"","","","","","","",
s k h,a j k,s g j,a f k,s j j,s j g};
P("\n\n\n\33[3A");
while (argc>1&&0!=(n=argv[1][m++])){
P(b[n>96?n-80:n-48]);P("\33[3A\33[3C");
}
P("\n\n\n");
}
You can save a couple characters by removing some newlines, but I don't care to.
That's 500 characters, or 482 if you take out newlines and argc>1&&
Requires VT100 escape code support and won't do more than 26 characters of output on an 80 column terminal.
PS I'd like to see more people show their output.
C# - 576 characters (w/o linebreaks)
There's probably a better way to do this, but here's my solution:
using C=System.Console;class Z{static void Main(){new Z();}int L=0;Z(){
try{var s=C.ReadLine().ToUpper();C.Clear();foreach(var c in s){int n=(
int)c;var p=(n==48?"_ ;| |;|_|":n==49?"; |; |":n==50?"_; _|;|_":n==51
?"_; _|; _|":n==52?";|_|; |":n==53?"_;|_; _|":n==54?"_;|_;|_|":n==55?
"_; |; |":n==56?"_;|_|;|_|":n==57?"_;|_|; _|":n==65?"_;|_|;| |":n==66
?";|_;|_|":n==67?"_;|;|_":n==68?"; _|;|_|":n==69?"_;|_;|_":n==70?"_;|_;|"
:";;").Split(';');P(0);C.Write(" "+p[0]);P(1);C.Write(p[1]);P(2);C.Write
(p[2]);L+=4;}C.WriteLine();}catch{}}void P(int t){C.SetCursorPosition(L,t);}}
Haskell, 259 chars.
Is Haskell bad for golf or is it me (my first golf)?
import Char
i=iterate
d b=map(`mod`b).i(`div`b)
z _ 0=' '
z a 1=a
r=take 3
main=
getLine>>=
putStr.unlines.foldl1(zipWith(++)).
map(r.map r.i(drop 3).take 9.zipWith z(cycle"|_|").(0:).d 2.
(d 256(0xddfd91edcd9cd97990f5*2^384+0x2d6df865ecbd*(2^520+2^776))!!).ord)
(split main to lines for readability)
Javascript 333 Characters When Packed
s=" ";
function r(p)
{
if(t[p]=="0")
return s;
return "_|_||_|".split("")[p];
}
function g(w){
a="";b=a;c=a;
z=[];
for(x=0;x<w.length;x++){
t=("000"+parseInt("6F095E5B397377497F7B7D37661F7674".substr(parseInt(w.substr(x,1),16)*2,2),16).toString(2)).slice(-7).split("");
a+=s+r(0)+s+s;
b+=r(1)+r(2)+r(3)+s;
c+=r(4)+r(5)+r(6)+s;
}
return a+"\n"+b+"\n"+c;
}
alert(g("0123456789deadbeef"));
dc - 172 chars
A bit late but a dc entry, almost to spec: it does only accept uppercase numbers, i.e. [0-9A-F] and may print extra 0s at the beginning. Anyway, here it is:
16iD9B4FE55FFBDFFA5BF5BAB774977sK
[ ][ _ ][ |][ _|][| ][|_ ][| |][|_|]8[1-ds_:al_d0<L]dsLx
?dsNZdsZ
40sr[[1-dlNr10r^/10%80r^lKr/80%lr/8%;aPd0<L]dsLxAP]dsAx
lZ8srlAxlZ1srlAx
A little explanation (line breaks are not required):
The constant 0xD9B4FE55FFBDFFA5BF5BAB774977 encodes each digit in 7 bit, e.g. the number '4' is encoded as 0 111 010, meaning use the string '0' for the top (''), string 7 for the middle ('|_|') and string 2 for the bottom ('|').
The second line defines the strings and stores them in array 'a'
The third lines handles the input and checks how long the number is.
The fourth line does the computation. It created the "subroutine" A and execute it for the first line. The subroutine extracts the appropriate digit (1-dlNr10r^/10), then extracts the 7-bit encoding data (80r^lKr/80%), then takes the appropriate part for the specific line (lr/8%) loads the string and prints it (;aP) then it loops over all the digits (d0<L)
The last line does the same for lines 2 and 3 of the display.
Scala, 234 bytes
val a=Seq("|_|"," _ "," |","| |"," _|","| ","|_ "," ")
val m=argv(0).toLowerCase.map(_-'0').map(i=>if(i<10)i else i-39)
for(s<-Seq(0,16,32))
println(m.map(i=>a("171171111117171132440662000654660264240204306065"(i+s)-'0')).mkString)
Code is quite straight-forward: all 9 possible segments are packed into array and mapping between hex number and position. Probably, it could be packed better.
The code to calculate magic numbers:
val s = " _ _ *all numbers in one line here* |_||_ | "
val gl = (0 to s.size / 3-1).map(c => s.substring(c*3, c*3+3 ))
// gl now contains flat list of string of 3 chars each
val arr=gl.toSet.toArray // remove duplicates
// for each segment string find corresponding packed index
val n = gl.map( arr indexOf _).mkString
as result, n is the magic number, arr is the array of strings
Windows PowerShell, 157
$i=[char[]]"$input"
'☺ ☺☺ ☺☺☺☺☺☺ ☺ ☺☺','♠☻♥♥♦♣♣☻♦♦♦♣•♥♣♣','♦☻♣♥☻♥♦☻♦♥♠♦♣♦♣•'|%{$c=$_
""+($i|%{('···0·_·0··|0·_|0|_|0|_·0|·|0|··'-split0)[$c[("0x$_"|iex)]]})}
Compiles with -Wall and can be understood; not very short (~400 chars). In a serious implementation, I'd pull the char->index out of the output part (and store the indices in a buffer rather than the chars). Global r is initialized to 0, which it wouldn't if it were a local in main.
#include <stdio.h>
typedef char const* R;
R _=" _ ",S=" ",I=" |",J=" _|",L="|_ ",U="|_|",N="| |",C="| ";
R s[][16]={
{_,S,_,_,S,_,_,_,_,_,_,S,_,S,_,_},
{N,I,J,J,U,L,L,I,U,U,U,L,C,J,L,L},
{U,I,L,J,I,J,U,I,U,J,N,U,L,U,L,C}};
int r,c,i;
int main(){
char b[999];
scanf("%s",b);
for(;r<3;++r)
for(c=0;;) {
i=b[c++]-'0';
if (i>16) i-=7;
if (i>15) i-=32;
if (i<0||i>15){putchar('\n');break;}
printf("%s",s[r][i]);
}
return 0;
}
Python one-liner (322 characters)
print(lambda l:(lambda s:'\n'.join([' '.join(x) for x in zip(*[l[c].split('\n')
for c in s])])))(dict(zip('0123456789abcdef', 'eJxdjrEBwDAIw3au0Ac9iUd0fJM2DTQD'
'g5ExJgkxTOMKYIzPDDUYORlNsZ3zppwuXsqt/pmmjVmZ\nH6M+9BTXZvU8Umg9fd03SOgvPw=='
.decode('base64').decode('zlib').split('\n/\n'))))(__import__('sys').argv[-1]
.lower())
Most of the length due to me being lazy and using zlib and base64 builtins for the lookup table. Run it from the command line like this:
$ python golf.py fedcba9876543210
PHP, 232 characacters
$d=str_split(' _ | ||_ |_| _| || 124066153155046135134166144145142034173054133137',3);
foreach(str_split(strtolower($s))as$c){
$c=hexdec($c)+8;$r[0].=$d[$d[$c][0]];$r[1].=$d[$d[$c][1]];$r[2].=$d[$d[$c][2]];i
}
echo implode("\n",$r);
Explanation
# Array containing possible lines
$d=array(
0 => ' ',
1 => ' _ ',
2 => '| |',
3 => '|_ ',
4 => '|_|',
5 => ' _|',
6 => ' |',
7 => '| '
);
# Array mapping characters to 3 lines
$m=array(
0 => '124', # i.e. The character '0' is represented by $d[1], $d[2] and $d[4]
1 => '066',
2 => '153',
3 => '155',
4 => '046',
5 => '135',
6 => '134',
7 => '166',
8 => '144',
9 => '145',
a => '142',
b => '034',
c => '173',
d => '054',
e => '133',
f => '137',
);
# traverse $s and append to array $r
foreach (str_split(strtolower($s)) as $c) {
$r[0].=$d[$m[$c][0]];
$r[1].=$d[$m[$c][1]];
$r[2].=$d[$m[$c][2]];
}
# echo $r
echo implode("\n",$r);
Optimizations:
The arrays are generated dynamically using str_split()
Both arrays are joined into one
Characters are mapped numerically using hexdec()
JavaScript, 309 304 bytes.
Requires that no prototype functions are added to String/Array.
function d(b){r="";o='î$º¶tÖÞ¤þöü^Ê>ÚØ'.split("");p=b.split(r);a=[" 0 ",
"132","465"];c="036";for(k in a){for(var e in p)for(var f in a[k])r+=(U=
a[k][f])==" "?" ":(y=((Q=o[parseInt(p[e],16)].charCodeAt().toString(2))
.length==6?"00"+Q:Q.length==7?0+Q:Q)[U])==0?" ":c.indexOf(U)>-1?"_":"|";
r+="\n"}return r}
Test case (formatting due to first " marking a String:
d("0123456789abcdef");
" _ _ _ _ _ _ _ _ _ _ _ _
| | | _| _||_||_ |_ ||_||_||_||_ | _||_ |_
|_| ||_ _| | _||_| ||_| _|| ||_||_ |_||_ | "