Kode format apa yang digunakan untuk menampilkan nilai floating-point pada notasi specific?

Pertama, fungsinya, untuk mereka yang hanya menginginkan kode salin dan tempel:

def truncate(f, n): '''Truncates/pads a float f to n decimal places without rounding''' s = '{}'.format(f) if 'e' in s or 'E' in s: return '{0:.{1}f}'.format(f, n) i, p, d = s.partition('.') return '.'.join([i, (d+'0'*n)[:n]])

Ini valid dalam Python 2.7 dan 3.1+. Untuk versi yang lebih lama, itu tidak mungkin untuk mendapatkan efek "pembulatan cerdas" yang sama (setidaknya, bukan tanpa banyak kode rumit), tetapi pembulatan ke 12 tempat desimal sebelum pemotongan akan bekerja sebagian besar waktu:

def truncate(f, n): '''Truncates/pads a float f to n decimal places without rounding''' s = '%.12f' % f i, p, d = s.partition('.') return '.'.join([i, (d+'0'*n)[:n]])

Penjelasan

Inti dari metode yang mendasarinya adalah mengubah nilai menjadi string dengan presisi penuh dan kemudian memenggal semuanya di luar jumlah karakter yang diinginkan. Langkah terakhir itu mudah; itu bisa dilakukan dengan manipulasi string

i, p, d = s.partition('.') '.'.join([i, (d+'0'*n)[:n]])

atau modul decimal

str(Decimal(s).quantize(Decimal((0, (1,), -n)), rounding=ROUND_DOWN))

Langkah pertama, mengonversi menjadi string, cukup sulit karena ada beberapa pasang literal titik apung (mis. Apa yang Anda tulis dalam kode sumber) yang keduanya menghasilkan representasi biner yang sama namun harus dipotong secara berbeda. Misalnya, pertimbangkan 0,3 dan 0,29999999999999998. Jika Anda menulis 0.3 dalam program Python, kompiler mengkodekannya menggunakan format titik-mengambang IEEE ke dalam urutan bit (dengan asumsi float 64-bit)

0011111111010011001100110011001100110011001100110011001100110011

Ini adalah nilai terdekat dengan 0,3 yang secara akurat dapat direpresentasikan sebagai pelampung IEEE. Tetapi jika Anda menulis 0.29999999999999998 dalam program Python, kompiler menerjemahkannya menjadi nilai yang persis sama. Dalam satu kasus, Anda bermaksud memotongnya (menjadi satu digit) sebagai 0.3, sedangkan dalam kasus lain Anda berarti dipotong sebagai 0.2, tetapi Python hanya dapat memberikan satu jawaban. Ini adalah batasan mendasar dari Python, atau memang bahasa pemrograman apa pun tanpa evaluasi malas. Fungsi pemotongan hanya memiliki akses ke nilai biner yang tersimpan dalam memori komputer, bukan string yang Anda ketikkan ke dalam kode sumber.1

Jika Anda mendekode urutan bit kembali ke angka desimal, sekali lagi menggunakan format floating-point IEEE 64-bit, Anda mendapatkan

0.2999999999999999888977697537484345957637...

jadi implementasi naif akan muncul dengan 0.2 meskipun itu mungkin bukan yang Anda inginkan. Untuk selengkapnya tentang kesalahan representasi floating-point, lihat tutorial Python .

Sangat jarang bekerja dengan nilai floating-point yang sangat dekat dengan angka bulat tetapi sengaja tidak sama dengan angka bulat itu. Jadi ketika memotong, mungkin masuk akal untuk memilih representasi desimal "terbaik" dari semua yang bisa sesuai dengan nilai dalam memori. Python 2.7 dan yang lebih tinggi (tetapi bukan 3.0) menyertakan algoritma canggih untuk melakukan hal itu , yang dapat kita akses melalui operasi pemformatan string default.

'{}'.format(f)

Satu-satunya peringatan adalah bahwa ini bertindak seperti spesifikasi format g, dalam arti menggunakan notasi eksponensial (1.23e+4) jika jumlahnya besar atau cukup kecil. Jadi metodenya harus menangkap kasus ini dan menanganinya secara berbeda. Ada beberapa kasus di mana menggunakan spesifikasi format f sebagai gantinya menyebabkan masalah, seperti mencoba memotong 3e-10 ke 28 digit presisi (ini menghasilkan 0.0000000002999999999999999980), dan saya belum yakin bagaimana cara terbaik untuk mengatasinya.

Jika Anda benar-benar sedang bekerja dengan floats yang sangat dekat dengan angka bulat tetapi sengaja tidak sama dengan mereka (seperti 0,2999999999999999898 atau 99,959999999999994), ini akan menghasilkan beberapa positif palsu, yaitu akan membulatkan angka yang tidak Anda ketahui. Aku tidak ingin bulat. Dalam hal ini solusinya adalah menentukan presisi tetap.

'{0:.{1}f}'.format(f, sys.float_info.Dig + n + 2)

Jumlah digit presisi untuk digunakan di sini tidak terlalu penting, hanya perlu cukup besar untuk memastikan bahwa setiap pembulatan yang dilakukan dalam konversi string tidak "meningkatkan" nilai ke representasi desimal Nice. Saya pikir sys.float_info.Dig + n + 2 mungkin cukup dalam semua kasus, tetapi jika tidak 2 mungkin harus ditingkatkan, dan tidak ada salahnya untuk melakukannya.

Dalam versi Python sebelumnya (hingga 2.6, atau 3.0), pemformatan angka floating point jauh lebih kasar, dan secara teratur akan menghasilkan hal-hal seperti

>>> 1.1 1.1000000000000001

Jika ini adalah situasi Anda, jika Anda do ingin menggunakan representasi desimal "Bagus" untuk pemotongan, yang dapat Anda lakukan (sejauh yang saya tahu) adalah memilih beberapa angka, kurang dari perwakilan presisi penuh. dengan float, dan bulatkan angka ke banyak digit sebelum memotongnya. Pilihan khas adalah 12,

'%.12f' % f

tetapi Anda dapat menyesuaikan ini agar sesuai dengan angka yang Anda gunakan.1.

Yah ... aku berbohong. Secara teknis, Anda bisa memerintahkan Python untuk mem-parsing ulang kode sumbernya sendiri dan mengekstrak bagian yang sesuai dengan argumen pertama yang Anda berikan ke fungsi pemotongan. Jika argumen itu adalah floating-point literal, Anda bisa memotongnya dari sejumlah tempat setelah titik desimal dan mengembalikannya. Namun strategi ini tidak berfungsi jika argumennya adalah variabel, yang membuatnya tidak berguna. Berikut ini disajikan hanya untuk nilai hiburan:

Menggeneralisasi ini untuk menangani kasus di mana Anda memasukkan variabel tampak seperti penyebab yang hilang, karena Anda harus melacak mundur melalui eksekusi program sampai Anda menemukan literal titik-mengambang yang memberikan nilai pada variabel. Jika ada. Sebagian besar variabel akan diinisialisasi dari input pengguna atau ekspresi matematika, dalam hal ini semua representasi biner ada.

def trunc_introspect(f, n): '''Truncates/pads the float f to n decimal places by looking at the caller's source code''' current_frame = None caller_frame = None s = inspect.stack() try: current_frame = s[0] caller_frame = s[1] gen = tokenize.tokenize(io.BytesIO(caller_frame[4][caller_frame[5]].encode('utf-8')).readline) for token_type, token_string, _, _, _ in gen: if token_type == tokenize.NAME and token_string == current_frame[3]: next(gen) # left parenthesis token_type, token_string, _, _, _ = next(gen) # float literal if token_type == tokenize.NUMBER: try: cut_point = token_string.index('.') + n + 1 except ValueError: # no decimal in string return token_string + '.' + '0' * n else: if len(token_string) < cut_point: token_string += '0' * (cut_point - len(token_string)) return token_string[:cut_point] else: raise ValueError('Unable to find floating-point literal (this probably means you called {} with a variable)'.format(current_frame[3])) break finally: del s, current_frame, caller_frame

Generalizing this to handle the case where you pass in a variable seems like a lost cause, since you'd have to trace backwards through the program's execution until you find the floating-point literal which gave the variable its value. If there even is one. Most variables will be initialized from user input or mathematical expressions, in which case the binary representation is all there is.

You're Reading a Free Preview
Pages 7 to 15 are not shown in this preview.

Untuk menampilkan angka float pada program bahasa C, maka dapat digunakan tipe data float, double, dan long double pada pembuatan program tersebut.

Perbedaan Tipe Data

  • double memiliki dua kali lebih banyak presisi dibandingkan dengan float.
  • float adalah 32 bit IEEE 754 presisi tunggal floating point number bit, dimana float memiliki 7 decimal digit presisi.
  • double adalah 64 IEEE 754 double presisi floating point number, dimana double memiliki 15 desimal digit presisi.

Ambil contoh berikut ini: untuk persamaan kuadrat X2 - 4,0000000x + 3,9999999 = 0, nilai akar yang tepat untuk 10 digit signifikan adalah r1=2,000316228 dan r2=1,999683772.

// Perbedaan antara float dan

// double pada bahasa C

// Program bahasa C yang

// mendemonstrasikan

// nilai presisis float

// dan double

#include <stdio.h>

#include <math.h>

// Fungsi utilitas yang meng-

// kalkulasi akar kuadrat

// dari persamaan yang meng-

// gunakan nilai double

void double_solve(double a, double b, double c)

{

double d = b*b - 4.0*a*c;

double sd = sqrt(d);

double r1 = (-b + sd) / (2.0*a);

double r2 = (-b - sd) / (2.0*a);

printf("%.5f\t%.5f\n", r1, r2);

}

// Fungsi utilitas yang meng-

// kalkulasi akar kuadrat

// dari persamaan yang meng-

// gunakan nilai float

void float_solve(float a, float b, float c)

{

float d = b*b - 4.0f*a*c;

float sd = sqrtf(d);

float r1 = (-b + sd) / (2.0f*a);

float r2 = (-b - sd) / (2.0f*a);

printf("%.5f\t%.5f\n", r1, r2);

}

// Menjalankan program

int main()

{

float fa = 1.0f;

float fb = -4.0000000f;

float fc = 3.9999999f;

double da = 1.0;

double db = -4.0000000;

double dc = 3.9999999;

printf("persamaan akar dari x2"

" - 4.0000000 x + 3.9999999 ="

" 0 adalah : \n");

printf("untuk nilai float "

": \n");

float_solve(fa, fb, fc);

printf("untuk nilai double"

": \n");

double_solve(da, db, dc);

return 0;

}

persamaan akar dari x2 - 4.0000000 x + 3.9999999 = 0 adalah :
untuk nilai float :
2.00000    2.00000
untuk nilai double :
2.00032    1.99968

Page 2

Terdapat dua file header penting yang digunakan dalam bahasa C. Pertama, "<stdio.h>" adalah file header untuk standar input dan output, dan kedua "<stdlib.h>" adalah header file untuk standar library. Salah satu cara mudah untuk membedakan kedua file header tersebut adalah "<stdio.h>" mengandung deklarasi dari printf() dan scanf(), sementara "<stdlib.h>" mengandung deklarasi dari malloc() dan free(). Secara umum, perbedaan kedua file header tersebut adalah "<stdio.h>" mengandung informasi header untuk file yang berkaitan dengan fungsi nilai input output pada program, sedangkan "<stdlib.h>" mengandung informasi untuk fungsi alokasi memori dan pembebasan alokasi memori.

Perlu diingat pula bahwa, meskipun "<stdlib.h>" mengandung deklarasi dari tipe fungsi lainnya, namun hal tersebut tidak berkaitan dengan memori seperti atoi(), exit(), rand(), dan lain sebagainya. Namun untuk tujuan penyederhanaan, dapat diingat bahwa malloc() dan free() adalah untuk file header "<stdlib.h>".

Juga perlu dicatat bahwa, file header dapat mengandung tidak hanya fungsi deklarasi tetapi juga definsi dari konstanta dan variabel. Bahkan makro dan definition dari tipe data juga dapat ditambahkan ke dalam file header.

Video yang berhubungan

Postingan terbaru

LIHAT SEMUA