PDF:

Toán học mới với Java, Phần 1 : Các số thực
Elliotte Rusty Harold ([email protected])
Giáo sư
Polytechnic University
28 08 2009
Hãy tham gia cùng Elliotte Rusty Harold để xem những đặc trưng mới trong lớp
java.lang.Math cổ điền trong bài báo gồm 2 phần này. Phần 1 tập trung chủ yếu vào các
hàm toán học. Phần 2 sẽ khám phá những hàm được thiết kế cho các số dấu phảy động.
Xem thêm bài trong loạt bài này
Đôi khi bạn rất quen thuộc với một lớp đến mức mà bạn không để ý đến nó nữa. Nếu bạn có thể
viết dẫn chứng tài liệu cho java.lang.Foo, và Eclipse sẽ tự động hoàn thành những hàm cho bạn,
tại sao bạn lại phải cần đọc Javadoc của nó? Đó là kinh nghiệm mà tôi đã có với java.lang.Math,
một lớp mà tôi nghĩ là tôi đã biết thực sự rõ. Hãy tưởng tượng sự ngạc nhiên của tôi, lúc đó khi tôi
gần đây tình cờ được đọc Javadoc của nó sau gần suốt nửa thập kỷ và tôi nhận ra rằng lớp này đã
gấp đôi về kích cỡ với 20 phương thức mới mà tôi chưa bao giờ nghe tới. Rõ ràng đó là lúc phải có
một cái nhìn khác.
Phiên bản 5 của Java™ Language Specification đã thêm 10 phương thức mới vào java.lang.Math
(và người anh em của nó java.lang.StrictMath), và Java 6 đã thêm 10 phương thức khác nữa.
Trong bài báo này, tôi tập trung vào những hàm toán học đơn giản hơn đã được cung cấp, ví dụ như
là log10 và cosh. Trong phần 2, tôi sẽ khám phá những hàm khác nữa được thiết kế để hoạt động
trên các số dấu phảy động đối lập với các số thực trừu tượng.
Phân biệt giữa một số thực trừu tượng như là π hay 0.2 và một số double trong Java là điều rất
quan trọng. Trước hết, mô hình lý tưởng Platonic của số là hoàn toàn chính xác, trong khi Java giới
hạn một số lượng các bit cố định. Điều này rất quan trọng khi bạn xử lý các con số lẻ và lớn. Ví dụ,
số 2.000.000.001 (hai tỉ lẻ 1) có thể được trình bày chính xác như một int, nhưng không phải như
là một float. Điểm gần nhất mà bạn có thể đạt được trong một float là 2.0E9 — tức là 2 tỉ. Các
double sẽ làm tốt hơn bởi vì chúng có nhiều số bit hơn (đó là lí do mà bạn nên luôn luôn sử dụng
các double thay vì các float); nhưng vẫn có các giới hạn thực tế về độ chính xác của chúng.
Giới hạn thứ 2 của số học máy tính (của ngôn ngữ Java và các ngôn ngữ khác) là ở chỗ nó được
dựa trên hệ nhị phân hơn là hệ thập phân. Các phân số như là 1/5 và 7/50 mà có thể được trình
bày chính xác trong hệ thập phân (lần lượt 0.2 và 0.14) trở thành các phân số lặp đi lặp lại khi được
© Copyright IBM Corporation 2009
Toán học mới với Java, Phần 1: Các số thực
Nhẫn hiệu đăng ký
Trang 1 của 11
developerWorks®
ibm.com/developerWorks/vn/
trình bày trong chú giải nhị phân. Điều này hoàn toàn giống với cách 1/3 trở thành 0.3333333...
khi nó được trình bày dưới dạng thập phân. Trong cơ số 10, bất cứ phân số nào mà mẫu số có thừa
số nguyên tố là 5 và 2 (chứ không phải là số khác) đều có thể trình bày được một cách chính xác.
Trong cơ số 2, chỉ những phân số mà các phân số là lũy thừa của 2 thì có thể được trình bày chính
xác là 1/2, 1/4, 1/8, 1/16 và tương tự.
Những sự không chính xác là một trong những nguyên nhân lớn dẫn tới một lớp toán học được cần
đến lúc ban đầu. Chắc chắn bạn có thể xác định lượng giác và các hàm khác với những mở rộng
chuỗi Taylor không sử dụng bất cứ gì ngoài toán tử tiêu chuẩn + và * và một phép lặp đơn giản, như
trong Ví dụ 1:
Ví dụ 1. Tính các hàm sine với chuỗi Taylor
public class SineTaylor {
public static void main(String[] args) {
for (double angle = 0; angle <= 4*Math.PI; angle += Math.PI/8) {
System.out.println(degrees(angle) + "\t" + taylorSeriesSine(angle)
+ "\t" + Math.sin(angle));
}
}
public static double degrees(double radians) {
return 180 * radians/ Math.PI;
}
public static double taylorSeriesSine(double radians) {
double sine = 0;
int sign = 1;
for (int i = 1; i < 40; i+=2) {
sine += Math.pow(radians, i) * sign / factorial(i);
sign *= -1;
}
return sine;
}
private static double factorial(int i) {
double result = 1;
for (int j = 2; j <= i; j++) {
result *= j;
}
return result;
}
}
Ở đây, nó được bắt đầu khá tốt, có chăng cũng chỉ là một sự khác biệt nhỏ ở cuối dãy số thập
phân:
0.0
22.5
45.0
67.5
90.0
0.0
0.0
0.3826834323650897
0.7071067811865475
0.923879532511287
1.0000000000000002
0.3826834323650898
0.7071067811865475
0.9238795325112867
1.0
Tuy nhiên, khi các góc bắt đầu tăng lên, các lỗi cũng sẽ bắt đầu nhiều và phương pháp tiếp cận này
sẽ không còn hiệu quả nữa:
Toán học mới với Java, Phần 1: Các số thực
Trang 2 của 11
ibm.com/developerWorks/vn/
630.0000000000003
652.5000000000005
675.0000000000005
697.5000000000006
-1.0000001371557132
-0.9238801080153761
-0.7071090807463408
-0.3826922100671368
developerWorks®
-1.0
-0.9238795325112841
-0.7071067811865422
-0.3826834323650824
Chuỗi Taylor ở đây thực sự đã chứng minh được sự chính xác hơn tôi mong đợi. Tuy nhiên, khi góc
tăng tới 360 độ, 720 độ (4 pi radian) hoặc cao hơn nữa, thì chuỗi Taylor yêu cầu càng nhiều số hạng
để tính toán chính xác. Ngày càng nhiều thuật toán phức tạp được dùng bởi java.lang.Math để
tránh được điều này.
Chuỗi Taylor cũng không đạt hiệu quả so với hàm sine có sẵn của chip máy tính để bàn hiện đại
ngày nay. Các phép tính riêng biệt của hàm sine và của các hàm khác nhanh và chính xác yêu
cầu các thuật toán phải được thiết kế rất cẩn thận để tránh việc biến các lỗi nhỏ thành to. Thông
thường, các thuật toán này được cài sẵn trong phần cứng để cải thiện tốc độ nhanh hơn.Ví dụ, hầu
hết các chip X86 được bán ra trong vòng 10 năm qua đều có những bổ sung về phần cứng hàm
sine và cosine mà thế hệ chip X86 VM chỉ việc gọi ra hơn là phải tính toán chậm chạp dựa trên các
thao tác thô sơ ban đầu nữa. HotSpot lợi dụng những chỉ dẫn này để tăng đáng kể tốc độ các thao
tác tính lượng giác.
Các tam giác vuông và những tiên đề Ơclit
Mọi học sinh phổ thông học hình học đều đã học về định lý Pytago: Bình phương chiều dài của
cạnh huyền của một tam giác vuông bằng tổng bình phương chiều dài của hai cạnh góc vuông. Tức
2
2
2
là, c = a + b
Những ai trong chúng ta đã từng áp dụng định lý đó vào vật lý trong đại học hoặc toán cao cấp đều
biết rằng biểu thức này thể hiện được hơn rất nhiều điều chứ không chỉ dừng lại ở các tam giác
2
vuông. Thí dụ, cũng là bình phương trong tiên đề Ơclit về R , chiều dài của một vector hai chiều,
một phần của bất đẳng thức tam giác, và hơn nữa. (Thực ra, đây là những cách nhìn khác nhau về
cùng một vấn đề. Điểm quan trọng ở đây chính là tiên đề của Ơclit quan trọng hơn rất nhiều so với
lúc xem xét nó ban đầu.)
Java 5 đã thêm một hàm Math.hypot để thực hiện chính xác phép tính này, và đây là một ví dụ
điển hình giải thích vì sao một thư viện là rất hữu ích. Cách tiếp cận này sẽ xem xét vấn đề như
sau:
public static double hypot(double x, double y){
return Math.sqrt (x*x + y*y);
}
Mã trình thực tế là một cái gì đó phức tạp hơn, như trong Ví dụ 2. Điều đầu tiên mà bạn sẽ chú ý
đến đó là nó được viết bằng mã trình C gốc để đạt hiệu quả tối đa. Điều thứ 2 mà bạn cũng nên chú
ý đó là nó đang đạt tới những độ dài lớn để cố gắng giảm tối thiểu bất cứ lỗi nào có thể trong phép
tính này.Thực ra, các thuật toán khác nhau đang được chọn phụ thuộc vào kích thước tương đối
của x và y.
Ví dụ 2. Mã trình thực được thi hành Math.hypot
/*
Toán học mới với Java, Phần 1: Các số thực
Trang 3 của 11
developerWorks®
ibm.com/developerWorks/vn/
* ====================================================
* Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
*
* Developed at SunSoft, a Sun Microsystems, Inc. business.
* Permission to use, copy, modify, and distribute this
* software is freely granted, provided that this notice
* is preserved.
* ====================================================
*/
#include "fdlibm.h"
#ifdef __STDC__
double __ieee754_hypot(double x, double y)
#else
double __ieee754_hypot(x,y)
double x, y;
#endif
{
double a=x,b=y,t1,t2,y1,y2,w;
int j,k,ha,hb;
ha = __HI(x)&0x7fffffff;
/* high word of x */
hb = __HI(y)&0x7fffffff;
/* high word of y */
if(hb > ha) {a=y;b=x;j=ha; ha=hb;hb=j;} else {a=x;b=y;}
__HI(a) = ha;
/* a <- |a| */
__HI(b) = hb;
/* b <- |b| */
if((ha-hb)>0x3c00000) {return a+b;} /* x/y > 2**60 */
k=0;
if(ha > 0x5f300000) {
/* a>2**500 */
if(ha >= 0x7ff00000) {
/* Inf or NaN */
w = a+b;
/* for sNaN */
if(((ha&0xfffff)|__LO(a))==0) w = a;
if(((hb^0x7ff00000)|__LO(b))==0) w = b;
return w;
}
/* scale a and b by 2**-600 */
ha -= 0x25800000; hb -= 0x25800000;
k += 600;
__HI(a) = ha;
__HI(b) = hb;
}
if(hb < 0x20b00000) {
/* b < 2**-500 */
if(hb <= 0x000fffff) {
/* subnormal b or 0 */
if((hb|(__LO(b)))==0) return a;
t1=0;
__HI(t1) = 0x7fd00000;
/* t1=2^1022 */
b *= t1;
a *= t1;
k -= 1022;
} else {
/* scale a and b by 2^600 */
ha += 0x25800000;
/* a *= 2^600 */
hb += 0x25800000;
/* b *= 2^600 */
k -= 600;
__HI(a) = ha;
__HI(b) = hb;
}
}
/* medium size a and b */
w = a-b;
if (w>b) {
t1 = 0;
__HI(t1) = ha;
t2 = a-t1;
w = sqrt(t1*t1-(b*(-b)-t2*(a+t1)));
} else {
a = a+a;
y1 = 0;
Toán học mới với Java, Phần 1: Các số thực
Trang 4 của 11
ibm.com/developerWorks/vn/
developerWorks®
__HI(y1) = hb;
y2 = b - y1;
t1 = 0;
__HI(t1) = ha+0x00100000;
t2 = a - t1;
w = sqrt(t1*y1-(w*(-w)-(t1*y2+t2*b)));
}
if(k!=0) {
t1 = 1.0;
__HI(t1) += (k<<20);
return t1*w;
} else return w;
}
Thực ra, việc bạn kết thúc bằng một hàm riêng biệt hoặc một trong số một vài hàm khác tương tự
như vậy phụ thuộc vào những chi tiết của JVM trên nền tảng của bạn. Tuy nhiên có nhiều khả năng
rằng đây là mã trình được tạo ra trong tiêu chuẩn JDK của Sun.(Các thực thi khác của JDK nếu có
thể sẽ được tự do cải tiến dựa trên tiêu chuẩn này.)
Mã trình này (và hầu hết mã trình toán học gốc khác trong thư viện Java Development Library) đều
có nguồn gốc từ thư viện mã nguồn mở fdlibm mà đã được viết ở Sun cách đây khoảng 15 năm.
Thư viện này được thiết kế để thực thi dấu phảy động IEE754 một cách chính xác và có những
phép tính chính xác, thậm chí phải hy sinh một tính hiệu quả nào đó.
Logarit cơ số 10
Một logarit cho bạn biết lũy thừa nào một cơ số phải tăng lên để cho ra một giá trị đã định. Nghĩa
là, nó là đảo ngược của hàm Math.pow(). Logarit cơ số 10 thường xuất hiện trong các ứng dụng kỹ
nghệ. Logarit cơ số e (hay còn gọi là logarit tự nhiên) xuất hiện trong phép tính lợi ích chung, và
nhiều ứng dụng toán học và khoa học khác. Logarit cơ số 2 thường xuất hiện trong phân tích thuật
toán.
Lớp Math đã có một hàm logarit tự nhiên từ phiên bản Java 1.0. Tức là, với một đối số x, hàm
logarit tự nhiên sẽ trả lại lũy thừa mà cơ số e phải được tăng lên để cho giá trị x. Đáng buồn thay,
hàm logarit tự nhiên của ngôn ngữ Java (và ngôn ngữ C, Fortran, và Basic) bị đặt tên sai là log().
Trong mọi sách giáo khoa toán mà tôi đã từng đọc, log là một hàm logarit cơ số 10, trong khi ln
là một hàm logarit cơ số e và lg là một hàm logarit cơ số 2. Bây giờ đã quá muộn để sửa điều này,
nhưng Java 5 đã thêm một hàm log10() mà lấy hàm logarit cơ số 10 thay vì cơ số e.
Ví dụ 3 là một chương trình đơn giản để in hàm logarit cơ số 2, 10 và e của dãy số nguyên từ 1 đến
100:
Toán học mới với Java, Phần 1: Các số thực
Trang 5 của 11
developerWorks®
ibm.com/developerWorks/vn/
Ví dụ 3. Các hàm logarit với nhiều cơ số khác nhau từ 1 đến 100
public class Logarithms {
public static void main(String[] args) {
for (int i = 1; i <= 100; i++) {
System.out.println(i + "\t" +
Math.log10(i) + "\t" +
Math.log(i) + "\t" +
lg(i));
}
}
public static double lg(double x) {
return Math.log(x)/Math.log(2.0);
}
}
Đât là 10 dòng đầu của kết quả:
1
2
3
4
5
6
7
8
9
10
0.0
0.3010299956639812
0.47712125471966244
0.6020599913279624
0.6989700043360189
0.7781512503836436
0.8450980400142568
0.9030899869919435
0.9542425094393249
1.0
0.0
0.0
0.6931471805599453
1.0
1.0986122886681096 1.584962500721156
1.3862943611198906
2.0
1.6094379124341003
2.321928094887362
1.791759469228055
2.584962500721156
1.9459101490553132
2.807354922057604
2.0794415416798357
3.0
2.1972245773362196
3.1699250014423126
2.302585092994046
3.3219280948873626
thông thường có những thông báo về các hàm logarit: lấy logarit của 0 hoặc bất kì
một số âm nào sẽ trả lại giá trị NaN.
Math.log10()
Các phép căn bậc 3
Tôi không thể nói rằng tôi đã từng cần lấy căn bậc 3 trong đời tôi, và tôi là một trong số ít người sử
dụng đại số học và hình học hàng ngày để đề cập đến những bước đột phá vào toán tích phân, vi
phân, các phương trình vi phân, và thậm chí hư số học. Kết quả là, tính hữu dụng của hàm này đã
không còn đối với tôi. Tuy nhiên, nếu bạn tìm ra một nhu cầu bất chợt nào để lấy căn bậc ba ở đâu
đó, bạn bây giờ có thể dùng đến nó — như Java 5 — với phương pháp Math.cbrt() . Ví dụ 4 minh
họa bằng cách lấy căn bậc 3 của dãy số nguyên từ -5 đến 5:
Ví dụ 4. Căn bậc 3 từ -5 đến 5
public class CubeRoots {
public static void main(String[] args) {
for (int i = -5; i <= 5; i++) {
System.out.println(Math.cbrt(i));
}
}
}
Đây là kết quả:
Toán học mới với Java, Phần 1: Các số thực
Trang 6 của 11
ibm.com/developerWorks/vn/
developerWorks®
-1.709975946676697
-1.5874010519681996
-1.4422495703074083
-1.2599210498948732
-1.0
0.0
1.0
1.2599210498948732
1.4422495703074083
1.5874010519681996
1.709975946676697
Như kết quả trên đã minh họa, một đặc trưng thú vị của căn bậc 3 so với căn bậc 2 là: Mỗi số thực
có chính xác một căn bậc ba thực. Hàm này chỉ trả lại NaN khi đối số của nó là NaN.
Các hàm lượng giác hypebol
Các hàm lượng giác hypebol cho ra tương ứng các hypebol giống như các hàm lượng giác cho ra
các hình tròn. Tức là, hãy tưởng tượng bạn vẽ những điểm này trên một mặt phẳng Đề-Các cho tất
cả các giá trị có thể của t:
x = r cos(t)
y = r sin(t)
Bạn sẽ vẽ ra được một vòng tròng với bán kính r. Ngược lại, giả sử bạn sử dụng thay thế bằng sinh
và cosh, như sau:
x = r cosh(t)
y = r sinh(t)
Bạn sẽ vẽ ra một hình hypebol chữ nhật có một điểm tiếp xúc gần nhất với gốc là r.
ix
-ix
ix
-
Một cách khác: Chỗ sin(x) có thể được viết là (e - e )/2i và cos(x) có thể được viết là (e + e
ix
)/2 , sinh và cosh là cái mà bạn nhận được khi bạn gỡ bỏ đơn vị ảo từ các công thức đó. Tức là,
x
-x
x
-x
sinh(x) = (e - e )/2 và cosh(x) = (e + e )/2.
Java 5 thêm tất cả ba: Math.cosh(), Math.sinh(), và Math.tanh(). Các hàm lượng giác hypebol
đảo ngược — acosh, asinh, và atanh — chưa được gộp vào.
Về bản chất, cosh(z) là phương trình cho hình một chiếc dây treo được nối hai đầu, gọi là một dây
xích (Catenary). Ví dụ 5 là một chương trình đơn giản vẽ hình một dây xích (Catenary) sử dụng
hàm Math.cosh :
Ví dụ 5. Vẽ một dây xích với Math.cosh()
import java.awt.*;
public class Catenary extends Frame {
private
private
private
private
static
static
static
static
final
final
final
final
int WIDTH = 200;
int HEIGHT = 200;
double MIN_X = -3.0;
double MAX_X = 3.0;
Toán học mới với Java, Phần 1: Các số thực
Trang 7 của 11
developerWorks®
ibm.com/developerWorks/vn/
private static final double MAX_Y = 8.0;
private Polygon catenary = new Polygon();
public Catenary(String title) {
super(title);
setSize(WIDTH, HEIGHT);
for (double x = MIN_X; x <= MAX_X; x += 0.1) {
double y = Math.cosh(x);
int scaledX = (int) (x * WIDTH/(MAX_X - MIN_X) + WIDTH/2.0);
int scaledY = (int) (y * HEIGHT/MAX_Y);
// in computer graphics, y extends down rather than up as in
// Caretesian coordinates' so we have to flip
scaledY = HEIGHT - scaledY;
catenary.addPoint(scaledX, scaledY);
}
}
public static void main(String[] args) {
Frame f = new Catenary("Catenary");
f.setVisible(true);
}
public void paint(Graphics g) {
g.drawPolygon(catenary);
}
}
Hình 1 thể hiện đường cong được vẽ:
Hình 1. Một đường cong trong mặt phẳng Đề-Các
Các hàm sinh, cosh, và tanh cũng xuất hiện trong các phép tính khác nhau trong tính tương đối
riêng biệt và tổng quát.
Đánh dấu
Hàm Math.signum chuyển đổi các số dương thành 1.0, các số âm thành -1.0, và các số 0 thành
0. Thực chất, nó trích dấu từ một số. Điều này có thể sẽ hữu ích khi bạn đang thi hành giao diện
Comparable.
Có một phiên bản float và một phiên bản double để duy trì loại đó. Lí do cho hàm khá rõ ràng
này là để nắm các trường hợp đặc biệt của toán học dấu phảy động, NaN, và số 0 dương và âm.
NaN được coi như là số 0, số 0 dương và âm sẽ trả lại số 0 dương và âm. Ví dụ, giả sử bạn phải đơn
thuần thi hành hàm này như trong Ví dụ 6:
Toán học mới với Java, Phần 1: Các số thực
Trang 8 của 11
ibm.com/developerWorks/vn/
developerWorks®
Ví dụ 6. Lỗi thi hành của Math.signum
public static double signum(double x) {
if (x == 0.0) return 0;
else if (x < 0.0) return -1.0;
else return 1.0;
}
Đầu tiên, phương pháp này sẽ trả lại tất cả các số 0 âm thành các số 0 dương. (Đúng, các số 0 âm
hơi kì lạ một chút, nhưng chúng là một phần cần thiết của thông số IEEE754.) Thứ hai, nó sẽ khẳng
định rằng NaN là dương. Sự thi hành thực tế được thể hiện trong Ví dụ 7 phức tạp và cẩn thận hơn
để nắm được các trường hợp góc kì lạ này:
Ví dụ 7. Thi hành đúng thực tế của Math.signum
public static double signum(double d) {
return (d == 0.0 || isNaN(d))?d:copySign(1.0, d);
}
public static double copySign(double magnitude, double sign) {
return rawCopySign(magnitude, (isNaN(sign)?1.0d:sign));
}
public static double rawCopySign(double magnitude, double sign) {
return Double.longBitsToDouble((Double.doubleToRawLongBits(sign) &
(DoubleConsts.SIGN_BIT_MASK)) |
(Double.doubleToRawLongBits(magnitude) &
(DoubleConsts.EXP_BIT_MASK |
DoubleConsts.SIGNIF_BIT_MASK)));
}
Làm ít, hưởng nhiều
Mã trình hiệu quả nhất là mã trình mà bạn chưa bao giờ viết. Đừng làm theo những gì mà các
chuyên gia đã làm. Mã trình sử dụng các hàm java.lang.Math , mới và cũ, sẽ nhanh hơn, hiệu quả
hơn, và chính xác hơn bất cứ cái gì mà bạn tự viết. Hãy sử dụng nó.
Toán học mới với Java, Phần 1: Các số thực
Trang 9 của 11
developerWorks®
ibm.com/developerWorks/vn/
Tài nguyên
Học tập
• "Java's new math, Part 2: Floating-point numbers" (Elliotte Rusty Harold, developerWorks,
January 2008): Đừng quên phần đăng thứ 2 của loạt bài này, khám phá những hàm được thiết
kế cho việc hoạt động trên các số dấu phảy động.
• Types, Values, and Variables: Chương 4 của Java Language Specification bao quát số học
dấu phảy động.
• IEEE standard for binary floating-point arithmetic: Tiêu chuẩn IEEE 754 định nghĩa toán học
dấu phảy động trong hầu hết các bộ xử lý và các ngôn ngũ, bao gồm ngôn ngữ Java.
• java.lang.Math: Javadoc cho lớp cung cấp các hàm được thảo luận trong bài báo này.
• Bug 5005861: Một người dùng thất vọng yêu cầu các hàm lượng giác nhanh hơn trong JDK.
• Catenary: Wikipedia giải thích lịch sử và toán học đằng sau dây xích.
• Duyệt technology bookstore cho các sách về những chủ đề kĩ thuật này và những chủ đề
khác.
• developerWorks Java technology zone: Tìm hàng trăm bài báo về mọi chủ đề lập trình Java.
Lấy sản phẩm và công nghệ
• fdlibm: Một thư viện toán học C cho máy hỗ trợ dấu phảy động IEEE754, có sẵn từ kho
phần mềm toán học Netlib.
• OpenJDK: Nhìn vào mã nguồn của các lớp toán bên trong thi hành Java SE mã nguồn mở.
Thảo luận
• Ghi tên developerWorks blogs và tham gia vào developerWorks community.
Toán học mới với Java, Phần 1: Các số thực
Trang 10 của 11
ibm.com/developerWorks/vn/
developerWorks®
Đôi nét về tác giả
Elliotte Rusty Harold
Elliotte Rusty Harold xuất thân từ bang New Orleans nơi mà ông vẫn thỉnh thoảng
về thăm những lúc thảnh thơi. Tuy nhiên, ông đang cư trú gần Trung tâm University
Town Center, Irvine cùng với vợ ông là Beth và những chú mèo Charm (được đặt tên
theo hạt "charm quark" trong vật lý) và Marjorie (đặt tên theo tên của mẹ vợ ông).
Trang Web Cafe au Lait của ông đã trở thành một trong những trang Java độc lập nổi
tiếng nhất trên Internet, và trang Web phụ của ông, Cafe con Leche, đã trở thành một
trong những trang XML phổ biến nhất. Cuốn sách của ông gần đây nhất là Refactoring
HTML
© Copyright IBM Corporation 2009
(www.ibm.com/legal/copytrade.shtml)
Nhẫn hiệu đăng ký
(www.ibm.com/developerworks/vn/ibm/trademarks/)
Toán học mới với Java, Phần 1: Các số thực
Trang 11 của 11