Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
Tags
- StringUtils
- 이클립스 플러그인 개발
- Callable
- ACAP
- IPTV
- JCE
- RSA
- 자바
- date
- 자바 암호화
- sha1
- PKCS
- 한글조사
- 한글조사처리
- Log4J
- Instrumentation
- DAMO
- 암호학
- Java
- Executors
- ORM
- Runnable
- Executor
- PKCS#8
- Freemaker
- String
- xlet
- Postman
- mac
- AES
Archives
- Today
- Total
오늘은 어디로 갈까...
숫자(Number) 0x01 본문
자, 이제 실제로 유틸리티 클래스를 만들어 보자.
단순히 웹 어플리케이션 개발을 할 경우 실제적으로 많이 쓰이는 것은 문자열을 숫자형으로 변환하는 것이다.
문자열을 입력받아 자바 기본 숫자형으로 변환하는 클래스를 만들어보자
별로 쓸 일은 없겠지만 unsigned int 형을 다뤄보자. 자바에는 unsigned 형이 없다. 그래서 int형을 unsigned int 형 처럼 사용할려면 i & 0xfffffffL; 연산을 이용해서 long형에 담으면 부호없는 int 형 처럼 보인다.
테스트 케이스를 만들어보자.
0xFFFFFFFF는 int형일 경우 -1이다. 근데 잘 보면 비교값이 0xFFFFFFFFL 이다. 'L'이란 문자가 붙는다. 이 'L'은 long 타입의 숫자란 뜻이다. 그래서 0xFFFFFFFFL = 4294967295임으로 원하는 결과가 나오게 되는것이다.
이번에 비트(bit) 연산을 한번 해볼까.
'&'(AND) 연산은 두 값이 다 1일때만 1을, 아니면 0을 나타낸다.
예) 1011 & 1101 = 1001
'|'(OR) 연산은 두 값중 하나라도 1일때 1을, 둘다 0이면 면 0을 나타낸다.
예) 1011 & 1101 = 1111
shift 연산
'<<' 은 비트단위만큼 왼쪽으로 이동을 한다는 뜻이다. 오른쪽은 0으로 채운다.
예) 10111010 << 4 = 10100000
'>>' 은 비트단위만큼 오른쪽으로 이동을 한다는 뜻이다. 만일 최상위 비트가 1인 경우 왼쪽을 1로 채우고 아닐 경우 0으로 채운다.
예) 10111010 >> 4 = 11111011
00111010 >> 4 = 00000011
'>>>'은 비트단위만큼 오른쪽으로 이동을 한다는 뜻이다. 단, 무조건 왼쪽을 0으로 채운다.
예) 10111010 >>> 4 = 00001011
00111010 >>> 4 = 00000011
'~'은 보수로서 0을 1로, 1을 0으로 바꾼다.
자바에서는 shift 연산은 지원하는데, rotate 연산은 지원하지 않는다.(아마도..) 그래서 위의 연산을 가지고 roate를 구현해보자
덤으로 long형의 앞 워드(word)와 뒷 워드(word)를 추출하는것도 만들어보자.
단순히 웹 어플리케이션 개발을 할 경우 실제적으로 많이 쓰이는 것은 문자열을 숫자형으로 변환하는 것이다.
문자열을 입력받아 자바 기본 숫자형으로 변환하는 클래스를 만들어보자
/** * 문자열을 숫자(short)형으로 변환한다. * * <pre> * NumberUtils.toShort(null, 0) = 0 * NumberUtils.toShort("NaN", 0) = 0 * NumberUtils.toShort("1234", 0) = 1234 * </pre> * * @param value * @param defaultValue 기본값 * @return */ public static short toShort(String value, short defaultValue) { if (value == null) { return defaultValue; } short result = defaultValue; try { result = Short.parseShort(value); } catch (NumberFormatException e) { // ignore } return result; } /** * 문자열을 숫자(Short)형으로 변환한다. * * <pre> * NumberUtils.toShortObject(null) = null * NumberUtils.toShortObject("NaN") = null * NumberUtils.toShortObject("1234") = 1234 * </pre> * * @param value * @return */ public static Short toShortObject(String value) { if (value == null) { return null; } Short result = null; try { result = new Short(Short.parseShort(value)); } catch (NumberFormatException e) { // ignore } return result; } /** * 문자열을 숫자(Short)형으로 변환한다. * 단, 문자열은 패턴(pattern)과 일치해야한다. * 패턴과 일치하지 않을 경우에는 null을 반환한다. * * <pre> * NumberUtils.toShortObject(null, *) = null * NumberUtils.toShortObject("NaN", *) = null * NumberUtils.toShortObject("1,234", "#,###") = 1234 * NumberUtils.toShortObject("1234", "#,###") = null * NumberUtils.toShortObject("1234", null) = 1234 * </pre> * * @param value * @param pattern 패턴 * @return */ public static Short toShortObject(String value, String pattern) { if (value == null) { return null; } Short result = null; if (pattern != null) { DecimalFormat dFormat = new DecimalFormat(pattern); try { result = new Short(dFormat.parse(value).shortValue()); if (value.equals(dFormat.format(result)) == false) { result = null; } } catch (ParseException e) { // ignore } } else { try { result = new Short(Short.parseShort(value)); } catch (NumberFormatException e) { // ignore } } return result; } /** * 문자열을 숫자(int)형으로 변환한다. * * <pre> * NumberUtils.toInteger(null, 0) = 0 * NumberUtils.toInteger("NaN", 0) = 0 * NumberUtils.toInteger("1234", 0) = 1234 * </pre> * * @param value * @param defaultValue 기본값 * @return */ public static int toInteger(String value, int defaultValue) { if (value == null) { return defaultValue; } int result = defaultValue; try { result = Integer.parseInt(value); } catch (NumberFormatException e) { // ignore } return result; } /** * 문자열을 숫자(Integer)형으로 변환한다. * * <pre> * NumberUtils.toIntegerObject(null) = null * NumberUtils.toIntegerObject("NaN") = null * NumberUtils.toIntegerObject("1234") = 1234 * NumberUtils.toIntegerObject("-2147483649") = null * NumberUtils.toIntegerObject("-2147483648") = -2147483648 * NumberUtils.toIntegerObject("2147483647") = 2147483647 * NumberUtils.toIntegerObject("2147483648") = null * </pre> * * @param value * @return */ public static Integer toIntegerObject(String value) { if (value == null) { return null; } Integer result = null; try { result = new Integer(Integer.parseInt(value)); } catch (NumberFormatException e) { // ignore } return result; } /** * 문자열을 숫자(Integer)형으로 변환한다. * 단, 문자열은 패턴(pattern)과 일치해야한다. * 패턴과 일치하지 않을 경우에는 null을 반환한다. * * <pre> * NumberUtils.toIntegerObject(null, *) = null * NumberUtils.toIntegerObject("NaN", *) = null * NumberUtils.toIntegerObject("1,234", "#,###") = 1234 * NumberUtils.toIntegerObject("1234", "#,###") = null * NumberUtils.toIntegerObject("1234", null) = 1234 * </pre> * * @param value * @param pattern 패턴 * @return */ public static Integer toIntegerObject(String value, String pattern) { if (value == null) { return null; } Integer result = null; if (pattern != null) { DecimalFormat dFormat = new DecimalFormat(pattern); try { result = new Integer(dFormat.parse(value).intValue()); if (value.equals(dFormat.format(result)) == false) { result = null; } } catch (ParseException e) { // ignore } } else { try { result = new Integer(Integer.parseInt(value)); } catch (NumberFormatException e) { // ignore } } return result; } /** * 문자열을 숫자(long)형으로 변환한다. * * <pre> * NumberUtils.toLong(null, 0) = 0 * NumberUtils.toLong("NaN", 0) = 0 * NumberUtils.toLong("1234", 0) = 1234 * </pre> * * @param value * @param defaultValue 기본값 * @return */ public static long toLong(String value, long defaultValue) { long result = defaultValue; try { result = Long.parseLong(value); } catch (NumberFormatException e) { // ignore } return result; } /** * 문자열을 숫자(Long)형으로 변환한다. * * <pre> * NumberUtils.toLongObject(null) = null * NumberUtils.toLongObject("NaN") = null * NumberUtils.toLongObject("1234") = 1234 * </pre> * * @param value * @return */ public static Long toLongObject(String value) { Long result = null; try { result = new Long(Long.parseLong(value)); } catch (NumberFormatException e) { // ignore } return result; } /** * 문자열을 숫자(Long)형으로 변환한다. * 단, 문자열은 패턴(pattern)과 일치해야한다. * 패턴과 일치하지 않을 경우에는 null을 반환한다. * * <pre> * NumberUtils.toLongObject(null, *) = null * NumberUtils.toLongObject("NaN", *) = null * NumberUtils.toLongObject("1,234", "#,###") = 1234 * NumberUtils.toLongObject("1234", "#,###") = null * NumberUtils.toLongObject("1234", null) = 1234 * </pre> * * @param value * @param pattern 패턴 * @return */ public static Long toLongObject(String value, String pattern) { if (value == null) { return null; } Long result = null; if (pattern != null) { DecimalFormat dFormat = new DecimalFormat(pattern); try { result = new Long(dFormat.parse(value).longValue()); if (value.equals(dFormat.format(result)) == false) { result = null; } } catch (ParseException e) { // ignore } } else { try { result = new Long(Long.parseLong(value)); } catch (NumberFormatException e) { // ignore } } return result; } /** * 문자열을 숫자(float)형으로 변환한다. * * <pre> * NumberUtils.toFloat(null, 0) = 0.0 * NumberUtils.toFloat("NaN", 0) = 0.0 * NumberUtils.toFloat("1234.5", 0) = 1234.5 * </pre> * * @param value * @param defaultValue 기본값 * @return */ public static float toFloat(String value, float defaultValue) { if (value == null) { return defaultValue; } try { return Float.parseFloat(value); } catch (NumberFormatException e) { return defaultValue; } } /** * 문자열을 숫자(Float)형으로 변환한다. * * <pre> * NumberUtils.toFloatObject(null) = null * NumberUtils.toFloatObject("AAA") = null * NumberUtils.toFloatObject("NaN") = Float.NAN * NumberUtils.toFloatObject("1234.5") = 1234.5 * </pre> * * @param value * @return */ public static Float toFloatObject(String value) { if (value == null) { return null; } try { return new Float(Float.parseFloat(value)); } catch (NumberFormatException e) { return null; } } /** * 문자열을 숫자(Float)형으로 변환한다. * 단, 문자열은 패턴(pattern)과 일치해야한다. * 패턴과 일치하지 않을 경우에는 null을 반환한다. * * <pre> * NumberUtils.toFloatObject(null, *) = null * NumberUtils.toFloatObject("AAA", *) = null * NumberUtils.toFloatObject("NaN", *) = Float.NAN * NumberUtils.toFloatObject("1,234", "#,###.#") = 1234.0 * NumberUtils.toFloatObject("1,234.5", "#,###.#") = 1234.5 * NumberUtils.toFloatObject("1234.5", "#,###") = null * NumberUtils.toFloatObject("1234.5", null) = 1234.5 * </pre> * * @param value * @param pattern 패턴 * @return */ public static Float toFloatObject(String value, String pattern) { if (value == null) { return null; } Float result = null; if (pattern != null) { DecimalFormat dFormat = new DecimalFormat(pattern); try { result = new Float(dFormat.parse(value).floatValue()); if (value.equals(dFormat.format(result)) == false) { result = null; } } catch (ParseException e) { // ignore } } else { try { result = new Float(Float.parseFloat(value)); } catch (NumberFormatException e) { // ignore } } return result; } /** * 문자열을 숫자(double)형으로 변환한다. * * <pre> * NumberUtils.toDouble(null, 0) = 0.0 * NumberUtils.toDouble("AAA", 0) = 0.0 * NumberUtils.toDouble("NaN", 0) = 0.0 * NumberUtils.toDouble("1234.5", 0) = 1234.5 * </pre> * * @param value * @param defaultValue 기본값 * @return */ public static double toDouble(String value, double defaultValue) { if (value == null) { return defaultValue; } try { return Double.parseDouble(value); } catch (NumberFormatException e) { return defaultValue; } } /** * 문자열을 숫자(Double)형으로 변환한다. * * <pre> * NumberUtils.toDoubleObject(null) = null * NumberUtils.toDoubleObject("NaN") = null * NumberUtils.toDoubleObject("1234.5") = 1234.5 * </pre> * * @param value * @return */ public static Double toDoubleObject(String value) { if (value == null) { return null; } try { return new Double(Double.parseDouble(value)); } catch (NumberFormatException e) { return null; } } /** * 문자열을 숫자(Double)형으로 변환한다. * 단, 문자열은 패턴(pattern)과 일치해야한다. * 패턴과 일치하지 않을 경우에는 null을 반환한다. * * <pre> * NumberUtils.toDoubleObject(null, *) = null * NumberUtils.toDoubleObject("NaN", *) = null * NumberUtils.toDoubleObject("1,234", "#,###.#") = 1234.0 * NumberUtils.toDoubleObject("1,234.5", "#,###.#") = 1234.5 * NumberUtils.toDoubleObject("1234.5", "#,###") = null * NumberUtils.toDoubleObject("1234.5", null) = 1234.5 * </pre> * * @param value * @param pattern 패턴 * @return */ public static Double toDoubleObject(String value, String pattern) { if (value == null) { return null; } Double result = null; if (pattern != null) { DecimalFormat dFormat = new DecimalFormat(pattern); try { result = new Double(dFormat.parse(value).doubleValue()); if (value.equals(dFormat.format(result)) == false) { result = null; } } catch (ParseException e) { // ignore } } else { try { result = new Double(Double.parseDouble(value)); } catch (NumberFormatException e) { // ignore } } return result; }단순히 null 체크나, 변환 실패할 경우만 체크하고 나머지는 자바에서 기본적으로 제공해주는 parserXXX를 사용해서 어려운 부분이 없으니, 설명은 생략하도록하겠다.
별로 쓸 일은 없겠지만 unsigned int 형을 다뤄보자. 자바에는 unsigned 형이 없다. 그래서 int형을 unsigned int 형 처럼 사용할려면 i & 0xfffffffL; 연산을 이용해서 long형에 담으면 부호없는 int 형 처럼 보인다.
/** * 입력한 i값을 unsigned int로 변환한다. * 자바는 unsinged int가 없기때문에 long형으로 반환한다. * * <pre> * NumberUtils.unsignedInt(1) = 1 * NumberUtils.unsignedInt(0) = 0 * NumberUtils.unsignedInt(-1) = 4294967295 * </pre> * * @param i signed int * @return unsigned int */ public static long unsignedInt(int i) { return i & 0xFFFFFFFFL; }
테스트 케이스를 만들어보자.
@Test public void testUnsignedInt() { Assert.assertEquals(NumberUtils.unsignedInt(0xFFFFFFF0), 0xFFFFFFF0L); Assert.assertEquals(NumberUtils.unsignedInt(0xFFFFFFFF), 0xFFFFFFFFL); }
0xFFFFFFFF는 int형일 경우 -1이다. 근데 잘 보면 비교값이 0xFFFFFFFFL 이다. 'L'이란 문자가 붙는다. 이 'L'은 long 타입의 숫자란 뜻이다. 그래서 0xFFFFFFFFL = 4294967295임으로 원하는 결과가 나오게 되는것이다.
이번에 비트(bit) 연산을 한번 해볼까.
'&'(AND) 연산은 두 값이 다 1일때만 1을, 아니면 0을 나타낸다.
예) 1011 & 1101 = 1001
'|'(OR) 연산은 두 값중 하나라도 1일때 1을, 둘다 0이면 면 0을 나타낸다.
예) 1011 & 1101 = 1111
shift 연산
'<<' 은 비트단위만큼 왼쪽으로 이동을 한다는 뜻이다. 오른쪽은 0으로 채운다.
예) 10111010 << 4 = 10100000
'>>' 은 비트단위만큼 오른쪽으로 이동을 한다는 뜻이다. 만일 최상위 비트가 1인 경우 왼쪽을 1로 채우고 아닐 경우 0으로 채운다.
예) 10111010 >> 4 = 11111011
00111010 >> 4 = 00000011
'>>>'은 비트단위만큼 오른쪽으로 이동을 한다는 뜻이다. 단, 무조건 왼쪽을 0으로 채운다.
예) 10111010 >>> 4 = 00001011
00111010 >>> 4 = 00000011
'~'은 보수로서 0을 1로, 1을 0으로 바꾼다.
자바에서는 shift 연산은 지원하는데, rotate 연산은 지원하지 않는다.(아마도..) 그래서 위의 연산을 가지고 roate를 구현해보자
덤으로 long형의 앞 워드(word)와 뒷 워드(word)를 추출하는것도 만들어보자.
/** * <p> * long 형의 앞 워드(word=4byte)를 추출한다. * </p> * * @param l * @return */ public static int extractW0(long l) { return (int) (l >> 32); } /** * <p> * long 형의 뒤 워드(word=4byte)를 추출한다. * </p> * * @param l * @return */ public static int extractW1(long l) { return (int) l; } /** * <p> * 지정한 거리만큼 왼쪽으로 로테이트(rotate)한다. * </p> * * @param i * @param distance * 로테이트 할 비트 수 * @return */ public static int rotateLeft(int i, int distance) { return (i << distance) | (i >>> -distance); } /** * <p> * 지정한 거리만큼 오른쪽으로 로테이트(rotate)한다. * </p> * * @param i * @param distance * 로테이트 할 비트 수 * @return */ public static int rotateRight(int i, int distance) { return (i >>> distance) | (i << -distance); } /** * <p> * 지정한 거리만큼 왼쪽으로 로테이트(rotate)한다. * </p> * * * @param i * @param distance * 로테이트 할 비트 수 * @return */ public static long rotateLeft(long i, int distance) { return (i << distance) | (i >>> -distance); } /** * <p> * 지정한 거리만큼 오른쪽으로 로테이트(rotate)한다. * </p> * * @param i * @param distance * 로테이트 할 비트 수 * @return */ public static long rotateRight(long i, int distance) { return (i >>> distance) | (i << -distance); }
@Test public void testExtractW0() { Assert.assertEquals(NumberUtils.extractW0(0xFFFFFFFF00000000L), 0xFFFFFFFF); Assert.assertEquals(NumberUtils.extractW0(0x00000001FFFFFFFFL), 0x00000001); Assert.assertEquals(NumberUtils.extractW0(0x00000000FFFFFFFFL), 0x00000000); } @Test public void testExtractW1() { Assert.assertEquals(NumberUtils.extractW1(0x00000000FFFFFFFFL), 0xFFFFFFFF); Assert.assertEquals(NumberUtils.extractW1(0xFFFFFFFF00000000L), 0x00000000); Assert.assertEquals(NumberUtils.extractW1(0xFFFFFFFF00000001L), 0x00000001); } @Test public void testRotateLeftIntInt() { Assert.assertEquals(NumberUtils.rotateLeft(0xF2AB34CD, 4), 0x2AB34CDF); Assert.assertEquals(NumberUtils.rotateLeft(0xF2AB34CD, 8), 0xAB34CDF2); Assert.assertEquals(NumberUtils.rotateLeft(0xF2AB34CD, 16), 0x34CDF2AB); Assert.assertEquals(NumberUtils.rotateLeft(0x02AB34CD, 4), 0x2AB34CD0); } @Test public void testRotateRightIntInt() { Assert.assertEquals(NumberUtils.rotateRight(0xF2AB34CD, 4), 0xDF2AB34C); Assert.assertEquals(NumberUtils.rotateRight(0xF2AB34CD, 8), 0xCDF2AB34); Assert.assertEquals(NumberUtils.rotateRight(0xF2AB34CD, 16), 0x34CDF2AB); Assert.assertEquals(NumberUtils.rotateRight(0x02AB34CD, 4), 0xD02AB34C); } @Test public void testRotateLeftLongInt() { Assert.assertEquals(NumberUtils.rotateLeft(0xF2AB34CD00000000L, 4), 0x2AB34CD00000000FL); Assert.assertEquals(NumberUtils.rotateLeft(0xF2AB34CD00000000L, 8), 0xAB34CD00000000F2L); Assert.assertEquals(NumberUtils.rotateLeft(0xF2AB34CD00000000L, 16), 0x34CD00000000F2ABL); Assert.assertEquals(NumberUtils.rotateLeft(0x02AB34CD00000000L, 4), 0x2AB34CD000000000L); } @Test public void testRotateRightLongInt() { Assert.assertEquals(NumberUtils.rotateRight(0xF2AB34CD00000000L, 4), 0x0F2AB34CD0000000L); Assert.assertEquals(NumberUtils.rotateRight(0xF2AB34CD00000000L, 8), 0x00F2AB34CD000000L); Assert.assertEquals(NumberUtils.rotateRight(0xF2AB34CD00000000L, 16), 0x0000F2AB34CD0000L); Assert.assertEquals(NumberUtils.rotateRight(0x02AB34CD00000000L, 4), 0x002AB34CD0000000L); }