mirror of
https://github.com/LCTT/TranslateProject.git
synced 2024-12-26 21:30:55 +08:00
Merge remote-tracking branch 'LCTT/master'
This commit is contained in:
commit
2ab7bd4021
@ -1,5 +1,5 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: ( )
|
||||
[#]: translator: (geekpi)
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
|
@ -1,5 +1,5 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: ( )
|
||||
[#]: translator: (heguangzhi)
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
@ -227,7 +227,7 @@ via: https://www.networkworld.com/article/3527420/how-to-find-what-you-re-lookin
|
||||
|
||||
作者:[Sandra Henry-Stocker][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[译者ID](https://github.com/译者ID)
|
||||
译者:[heguangzhi](https://github.com/heguangzhi)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
@ -1,747 +0,0 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: ( )
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (Using C and C++ for data science)
|
||||
[#]: via: (https://opensource.com/article/20/2/c-data-science)
|
||||
[#]: author: (Cristiano L. Fontana https://opensource.com/users/cristianofontana)
|
||||
|
||||
Using C and C++ for data science
|
||||
======
|
||||
Let's work through common data science task with C99 and C++11.
|
||||
![metrics and data shown on a computer screen][1]
|
||||
|
||||
While languages like [Python][2] and [R][3] are increasingly popular for data science, C and C++ can be a strong choice for efficient and effective data science. In this article, we will use [C99][4] and [C++11][5] to write a program that uses the [Anscombe’s quartet][6] dataset, which I'll explain about next.
|
||||
|
||||
I wrote about my motivation for continually learning languages in an article covering [Python and GNU Octave][7], which is worth reviewing. All of the programs are meant to be run on the [command line][8], not with a [graphical user interface][9] (GUI). The full examples are available in the [polyglot_fit repository][10].
|
||||
|
||||
### The programming task
|
||||
|
||||
The program you will write in this series:
|
||||
|
||||
* Reads data from a [CSV file][11]
|
||||
* Interpolates the data with a straight line (i.e., _f(x)=m ⋅ x + q_)
|
||||
* Plots the result to an image file
|
||||
|
||||
|
||||
|
||||
This is a common situation that many data scientists have encountered. The example data is the first set of [Anscombe's quartet][6], shown in the table below. This is a set of artificially constructed data that gives the same results when fitted with a straight line, but their plots are very different. The data file is a text file with tabs as column separators and a few lines as a header. This task will use only the first set (i.e., the first two columns).
|
||||
|
||||
[**Anscombe's quartet**][6]
|
||||
|
||||
I
|
||||
|
||||
II
|
||||
|
||||
III
|
||||
|
||||
IV
|
||||
|
||||
x
|
||||
|
||||
y
|
||||
|
||||
x
|
||||
|
||||
y
|
||||
|
||||
x
|
||||
|
||||
y
|
||||
|
||||
x
|
||||
|
||||
y
|
||||
|
||||
10.0
|
||||
|
||||
8.04
|
||||
|
||||
10.0
|
||||
|
||||
9.14
|
||||
|
||||
10.0
|
||||
|
||||
7.46
|
||||
|
||||
8.0
|
||||
|
||||
6.58
|
||||
|
||||
8.0
|
||||
|
||||
6.95
|
||||
|
||||
8.0
|
||||
|
||||
8.14
|
||||
|
||||
8.0
|
||||
|
||||
6.77
|
||||
|
||||
8.0
|
||||
|
||||
5.76
|
||||
|
||||
13.0
|
||||
|
||||
7.58
|
||||
|
||||
13.0
|
||||
|
||||
8.74
|
||||
|
||||
13.0
|
||||
|
||||
12.74
|
||||
|
||||
8.0
|
||||
|
||||
7.71
|
||||
|
||||
9.0
|
||||
|
||||
8.81
|
||||
|
||||
9.0
|
||||
|
||||
8.77
|
||||
|
||||
9.0
|
||||
|
||||
7.11
|
||||
|
||||
8.0
|
||||
|
||||
8.84
|
||||
|
||||
11.0
|
||||
|
||||
8.33
|
||||
|
||||
11.0
|
||||
|
||||
9.26
|
||||
|
||||
11.0
|
||||
|
||||
7.81
|
||||
|
||||
8.0
|
||||
|
||||
8.47
|
||||
|
||||
14.0
|
||||
|
||||
9.96
|
||||
|
||||
14.0
|
||||
|
||||
8.10
|
||||
|
||||
14.0
|
||||
|
||||
8.84
|
||||
|
||||
8.0
|
||||
|
||||
7.04
|
||||
|
||||
6.0
|
||||
|
||||
7.24
|
||||
|
||||
6.0
|
||||
|
||||
6.13
|
||||
|
||||
6.0
|
||||
|
||||
6.08
|
||||
|
||||
8.0
|
||||
|
||||
5.25
|
||||
|
||||
4.0
|
||||
|
||||
4.26
|
||||
|
||||
4.0
|
||||
|
||||
3.10
|
||||
|
||||
4.0
|
||||
|
||||
5.39
|
||||
|
||||
19.0
|
||||
|
||||
12.50
|
||||
|
||||
12.0
|
||||
|
||||
10.84
|
||||
|
||||
12.0
|
||||
|
||||
9.13
|
||||
|
||||
12.0
|
||||
|
||||
8.15
|
||||
|
||||
8.0
|
||||
|
||||
5.56
|
||||
|
||||
7.0
|
||||
|
||||
4.82
|
||||
|
||||
7.0
|
||||
|
||||
7.26
|
||||
|
||||
7.0
|
||||
|
||||
6.42
|
||||
|
||||
8.0
|
||||
|
||||
7.91
|
||||
|
||||
5.0
|
||||
|
||||
5.68
|
||||
|
||||
5.0
|
||||
|
||||
4.74
|
||||
|
||||
5.0
|
||||
|
||||
5.73
|
||||
|
||||
8.0
|
||||
|
||||
6.89
|
||||
|
||||
### The C way
|
||||
|
||||
[C][12] is a general-purpose programming language that is among the most popular languages in use today (according to data from the [TIOBE Index][13], [RedMonk Programming Language Rankings][14], [Popularity of Programming Language Index][15], and [State of the Octoverse of GitHub][16]). It is a quite old language (circa 1973), and many successful programs were written in it (e.g., the Linux kernel and Git to name just two). It is also one of the closest languages to the inner workings of the computer, as it is used to manipulate memory directly. It is a [compiled language][17]; therefore, the source code has to be translated by a [compiler][18] into [machine code][19]. Its [standard library][20] is small and light on features, so other libraries have been developed to provide missing functionalities.
|
||||
|
||||
It is the language I use the most for [number crunching][21], mostly because of its performance. I find it rather tedious to use, as it needs a lot of [boilerplate code][22], but it is well supported in various environments. The C99 standard is a recent revision that adds some nifty features and is well supported by compilers.
|
||||
|
||||
I will cover the necessary background of C and C++ programming along the way so both beginners and advanced users can follow along.
|
||||
|
||||
#### Installation
|
||||
|
||||
To develop with C99, you need a compiler. I normally use [Clang][23], but [GCC][24] is another valid open source compiler. For linear fitting, I chose to use the [GNU Scientific Library][25]. For plotting, I could not find any sensible library, and therefore this program relies on an external program: [Gnuplot][26]. The example also uses a dynamic data structure to store data, which is defined in the [Berkeley Software Distribution][27] (BSD).
|
||||
|
||||
Installing in [Fedora][28] is as easy as running:
|
||||
|
||||
|
||||
```
|
||||
`sudo dnf install clang gnuplot gsl gsl-devel`
|
||||
```
|
||||
|
||||
#### Commenting code
|
||||
|
||||
In C99, [comments][29] are formatted by putting **//** at the beginning of the line, and the rest of the line will be discarded by the interpreter. Alternatively, anything between **/*** and ***/** is discarded, as well.
|
||||
|
||||
|
||||
```
|
||||
// This is a comment ignored by the interpreter.
|
||||
/* Also this is ignored */
|
||||
```
|
||||
|
||||
#### Necessary libraries
|
||||
|
||||
Libraries are composed of two parts:
|
||||
|
||||
* A [header file][30] that contains a description of the functions
|
||||
* A source file that contains the functions' definitions
|
||||
|
||||
|
||||
|
||||
Header files are included in the source, while the libraries' sources are [linked][31] against the executable. Therefore, the header files needed for this example are:
|
||||
|
||||
|
||||
```
|
||||
// Input/Output utilities
|
||||
#include <stdio.h>
|
||||
// The standard library
|
||||
#include <stdlib.h>
|
||||
// String manipulation utilities
|
||||
#include <string.h>
|
||||
// BSD queue
|
||||
#include <sys/queue.h>
|
||||
// GSL scientific utilities
|
||||
#include <gsl/gsl_fit.h>
|
||||
#include <gsl/gsl_statistics_double.h>
|
||||
```
|
||||
|
||||
#### Main function
|
||||
|
||||
In C, the program must be inside a special function called **[main()][32]:**
|
||||
|
||||
|
||||
```
|
||||
int main(void) {
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
This differs from Python, as covered in the last tutorial, which will run whatever code it finds in the source files.
|
||||
|
||||
#### Defining variables
|
||||
|
||||
In C, variables have to be declared before they are used, and they have to be associated with a type. Whenever you want to use a variable, you have to decide what kind of data to store in it. You can also specify if you intend to use a variable as a constant value, which is not necessary, but the compiler can benefit from this information. From the [fitting_C99.c program][33] in the repository:
|
||||
|
||||
|
||||
```
|
||||
const char *input_file_name = "anscombe.csv";
|
||||
const char *delimiter = "\t";
|
||||
const unsigned int skip_header = 3;
|
||||
const unsigned int column_x = 0;
|
||||
const unsigned int column_y = 1;
|
||||
const char *output_file_name = "fit_C99.csv";
|
||||
const unsigned int N = 100;
|
||||
```
|
||||
|
||||
Arrays in C are not dynamic, in the sense that their length has to be decided in advance (i.e., before compilation):
|
||||
|
||||
|
||||
```
|
||||
`int data_array[1024];`
|
||||
```
|
||||
|
||||
Since you normally do not know how many data points are in a file, use a [singly linked list][34]. This is a dynamic data structure that can grow indefinitely. Luckily, the BSD [provides linked lists][35]. Here is an example definition:
|
||||
|
||||
|
||||
```
|
||||
struct data_point {
|
||||
double x;
|
||||
double y;
|
||||
|
||||
SLIST_ENTRY(data_point) entries;
|
||||
};
|
||||
|
||||
SLIST_HEAD(data_list, data_point) head = SLIST_HEAD_INITIALIZER(head);
|
||||
SLIST_INIT(&head);
|
||||
```
|
||||
|
||||
This example defines a **data_point** list comprised of structured values that contain both an **x** value and a **y** value. The syntax is rather complicated but intuitive, and describing it in detail would be too wordy.
|
||||
|
||||
#### Printing output
|
||||
|
||||
To print on the terminal, you can use the [**printf()**][36] function, which works like Octave's **printf()** function (described in the first article):
|
||||
|
||||
|
||||
```
|
||||
`printf("#### Anscombe's first set with C99 ####\n");`
|
||||
```
|
||||
|
||||
The **printf()** function does not automatically add a newline at the end of the printed string, so you have to add it. The first argument is a string that can contain format information for the other arguments that can be passed to the function, such as:
|
||||
|
||||
|
||||
```
|
||||
`printf("Slope: %f\n", slope);`
|
||||
```
|
||||
|
||||
#### Reading data
|
||||
|
||||
Now comes the hard part… There are some libraries for CSV file parsing in C, but none seemed stable or popular enough to be in the Fedora packages repository. Instead of adding a dependency for this tutorial, I decided to write this part on my own. Again, going into details would be too wordy, so I will only explain the general idea. Some lines in the source will be ignored for the sake of brevity, but you can find the complete example in the repository.
|
||||
|
||||
First, open the input file:
|
||||
|
||||
|
||||
```
|
||||
`FILE* input_file = fopen(input_file_name, "r");`
|
||||
```
|
||||
|
||||
Then read the file line-by-line until there is an error or the file ends:
|
||||
|
||||
|
||||
```
|
||||
while (![ferror][37](input_file) && ![feof][38](input_file)) {
|
||||
size_t buffer_size = 0;
|
||||
char *buffer = NULL;
|
||||
|
||||
getline(&buffer, &buffer_size, input_file);
|
||||
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
The [**getline()**][39] function is a nice recent addition from the [POSIX.1-2008 standard][40]. It can read a whole line in a file and take care of allocating the necessary memory. Each line is then split into [tokens][41] with the [**strtok()**][42] function. Looping over the token, select the columns that you want:
|
||||
|
||||
|
||||
```
|
||||
char *token = [strtok][43](buffer, delimiter);
|
||||
|
||||
while (token != NULL)
|
||||
{
|
||||
double value;
|
||||
[sscanf][44](token, "%lf", &value);
|
||||
|
||||
if (column == column_x) {
|
||||
x = value;
|
||||
} else if (column == column_y) {
|
||||
y = value;
|
||||
}
|
||||
|
||||
column += 1;
|
||||
token = [strtok][43](NULL, delimiter);
|
||||
}
|
||||
```
|
||||
|
||||
Finally, when the **x** and **y** values are selected, insert the new data point in the linked list:
|
||||
|
||||
|
||||
```
|
||||
struct data_point *datum = [malloc][45](sizeof(struct data_point));
|
||||
datum->x = x;
|
||||
datum->y = y;
|
||||
|
||||
SLIST_INSERT_HEAD(&head, datum, entries);
|
||||
```
|
||||
|
||||
The [**malloc()**][46] function dynamically allocates (reserves) some persistent memory for the new data point.
|
||||
|
||||
#### Fitting data
|
||||
|
||||
The GSL linear fitting function [**gsl_fit_linear()**][47] expects simple arrays for its input. Therefore, since you won't know in advance the size of the arrays you create, you must manually allocate their memory:
|
||||
|
||||
|
||||
```
|
||||
const size_t entries_number = row - skip_header - 1;
|
||||
|
||||
double *x = [malloc][45](sizeof(double) * entries_number);
|
||||
double *y = [malloc][45](sizeof(double) * entries_number);
|
||||
```
|
||||
|
||||
Then, loop over the linked list to save the relevant data to the arrays:
|
||||
|
||||
|
||||
```
|
||||
SLIST_FOREACH(datum, &head, entries) {
|
||||
const double current_x = datum->x;
|
||||
const double current_y = datum->y;
|
||||
|
||||
x[i] = current_x;
|
||||
y[i] = current_y;
|
||||
|
||||
i += 1;
|
||||
}
|
||||
```
|
||||
|
||||
Now that you are done with the linked list, clean it up. _Always_ release the memory that has been manually allocated to prevent a [memory leak][48]. Memory leaks are bad, bad, bad. Every time memory is not released, a garden gnome loses its head:
|
||||
|
||||
|
||||
```
|
||||
while (!SLIST_EMPTY(&head)) {
|
||||
struct data_point *datum = SLIST_FIRST(&head);
|
||||
|
||||
SLIST_REMOVE_HEAD(&head, entries);
|
||||
|
||||
[free][49](datum);
|
||||
}
|
||||
```
|
||||
|
||||
Finally, finally(!), you can fit your data:
|
||||
|
||||
|
||||
```
|
||||
gsl_fit_linear(x, 1, y, 1, entries_number,
|
||||
&intercept, &slope,
|
||||
&cov00, &cov01, &cov11, &chi_squared);
|
||||
const double r_value = gsl_stats_correlation(x, 1, y, 1, entries_number);
|
||||
|
||||
[printf][50]("Slope: %f\n", slope);
|
||||
[printf][50]("Intercept: %f\n", intercept);
|
||||
[printf][50]("Correlation coefficient: %f\n", r_value);
|
||||
```
|
||||
|
||||
#### Plotting
|
||||
|
||||
You must use an external program for the plotting. Therefore, save the fitting function to an external file:
|
||||
|
||||
|
||||
```
|
||||
const double step_x = ((max_x + 1) - (min_x - 1)) / N;
|
||||
|
||||
for (unsigned int i = 0; i < N; i += 1) {
|
||||
const double current_x = (min_x - 1) + step_x * i;
|
||||
const double current_y = intercept + slope * current_x;
|
||||
|
||||
[fprintf][51](output_file, "%f\t%f\n", current_x, current_y);
|
||||
}
|
||||
```
|
||||
|
||||
The Gnuplot command for plotting both files is:
|
||||
|
||||
|
||||
```
|
||||
`plot 'fit_C99.csv' using 1:2 with lines title 'Fit', 'anscombe.csv' using 1:2 with points pointtype 7 title 'Data'`
|
||||
```
|
||||
|
||||
#### Results
|
||||
|
||||
Before running the program, you must compile it:
|
||||
|
||||
|
||||
```
|
||||
`clang -std=c99 -I/usr/include/ fitting_C99.c -L/usr/lib/ -L/usr/lib64/ -lgsl -lgslcblas -o fitting_C99`
|
||||
```
|
||||
|
||||
This command tells the compiler to use the C99 standard, read the **fitting_C99.c** file, load the libraries **gsl** and **gslcblas**, and save the result to **fitting_C99**. The resulting output on the command line is:
|
||||
|
||||
|
||||
```
|
||||
#### Anscombe's first set with C99 ####
|
||||
Slope: 0.500091
|
||||
Intercept: 3.000091
|
||||
Correlation coefficient: 0.816421
|
||||
```
|
||||
|
||||
Here is the resulting image generated with Gnuplot.
|
||||
|
||||
![Plot and fit of the dataset obtained with C99][52]
|
||||
|
||||
### The C++11 way
|
||||
|
||||
[C++][53] is a general-purpose programming language that is also among the most popular languages in use today. It was created as a [successor of C][54] (in 1983) with an emphasis on [object-oriented programming][55] (OOP). C++ is commonly regarded as a superset of C, so a C program should be able to be compiled with a C++ compiler. This is not exactly true, as there are some corner cases where they behave differently. In my experience, C++ needs less boilerplate than C, but the syntax is more difficult if you want to develop objects. The C++11 standard is a recent revision that adds some nifty features and is more or less supported by compilers.
|
||||
|
||||
Since C++ is largely compatible with C, I will just highlight the differences between the two. If I do not cover a section in this part, it means that it is the same as in C.
|
||||
|
||||
#### Installation
|
||||
|
||||
The dependencies for the C++ example are the same as the C example. On Fedora, run:
|
||||
|
||||
|
||||
```
|
||||
`sudo dnf install clang gnuplot gsl gsl-devel`
|
||||
```
|
||||
|
||||
#### Necessary libraries
|
||||
|
||||
Libraries work in the same way as in C, but the **include** directives are slightly different:
|
||||
|
||||
|
||||
```
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
|
||||
extern "C" {
|
||||
#include <gsl/gsl_fit.h>
|
||||
#include <gsl/gsl_statistics_double.h>
|
||||
}
|
||||
```
|
||||
|
||||
Since the GSL libraries are written in C, you must inform the compiler about this peculiarity.
|
||||
|
||||
#### Defining variables
|
||||
|
||||
C++ supports more data types (classes) than C, such as a **string** type that has many more features than its C counterpart. Update the definition of the variables accordingly:
|
||||
|
||||
|
||||
```
|
||||
`const std::string input_file_name("anscombe.csv");`
|
||||
```
|
||||
|
||||
For structured objects like strings, you can define the variable without using the **=** sign.
|
||||
|
||||
#### Printing output
|
||||
|
||||
You can use the **printf()** function, but the **cout** object is more idiomatic. Use the operator **<<** to indicate the string (or objects) that you want to print with **cout**:
|
||||
|
||||
|
||||
```
|
||||
std::cout << "#### Anscombe's first set with C++11 ####" << std::endl;
|
||||
|
||||
...
|
||||
|
||||
std::cout << "Slope: " << slope << std::endl;
|
||||
std::cout << "Intercept: " << intercept << std::endl;
|
||||
std::cout << "Correlation coefficient: " << r_value << std::endl;
|
||||
```
|
||||
|
||||
#### Reading data
|
||||
|
||||
The scheme is the same as before. The file is opened and read line-by-line, but with a different syntax:
|
||||
|
||||
|
||||
```
|
||||
std::ifstream input_file(input_file_name);
|
||||
|
||||
while (input_file.good()) {
|
||||
std::string line;
|
||||
|
||||
getline(input_file, line);
|
||||
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
The line tokens are extracted with the same function as in the C99 example. Instead of using standard C arrays, use two [vectors][56]. Vectors are an extension of C arrays in the [C++ standard library][57] that allows dynamic management of memory without explicitly calling **malloc()**:
|
||||
|
||||
|
||||
```
|
||||
std::vector<double> x;
|
||||
std::vector<double> y;
|
||||
|
||||
// Adding an element to x and y:
|
||||
x.emplace_back(value);
|
||||
y.emplace_back(value);
|
||||
```
|
||||
|
||||
#### Fitting data
|
||||
|
||||
For fitting in C++, you do not have to loop over the list, as vectors are guaranteed to have contiguous memory. You can directly pass to the fitting function the pointers to the vectors buffers:
|
||||
|
||||
|
||||
```
|
||||
gsl_fit_linear(x.data(), 1, y.data(), 1, entries_number,
|
||||
&intercept, &slope,
|
||||
&cov00, &cov01, &cov11, &chi_squared);
|
||||
const double r_value = gsl_stats_correlation(x.data(), 1, y.data(), 1, entries_number);
|
||||
|
||||
std::cout << "Slope: " << slope << std::endl;
|
||||
std::cout << "Intercept: " << intercept << std::endl;
|
||||
std::cout << "Correlation coefficient: " << r_value << std::endl;
|
||||
```
|
||||
|
||||
#### Plotting
|
||||
|
||||
Plotting is done with the same approach as before. Write to a file:
|
||||
|
||||
|
||||
```
|
||||
const double step_x = ((max_x + 1) - (min_x - 1)) / N;
|
||||
|
||||
for (unsigned int i = 0; i < N; i += 1) {
|
||||
const double current_x = (min_x - 1) + step_x * i;
|
||||
const double current_y = intercept + slope * current_x;
|
||||
|
||||
output_file << current_x << "\t" << current_y << std::endl;
|
||||
}
|
||||
|
||||
output_file.close();
|
||||
```
|
||||
|
||||
And then use Gnuplot for the plotting.
|
||||
|
||||
#### Results
|
||||
|
||||
Before running the program, it must be compiled with a similar command:
|
||||
|
||||
|
||||
```
|
||||
`clang++ -std=c++11 -I/usr/include/ fitting_Cpp11.cpp -L/usr/lib/ -L/usr/lib64/ -lgsl -lgslcblas -o fitting_Cpp11`
|
||||
```
|
||||
|
||||
The resulting output on the command line is:
|
||||
|
||||
|
||||
```
|
||||
#### Anscombe's first set with C++11 ####
|
||||
Slope: 0.500091
|
||||
Intercept: 3.00009
|
||||
Correlation coefficient: 0.816421
|
||||
```
|
||||
|
||||
And this is the resulting image generated with Gnuplot.
|
||||
|
||||
![Plot and fit of the dataset obtained with C++11][58]
|
||||
|
||||
### Conclusion
|
||||
|
||||
This article provides examples for a data fitting and plotting task in C99 and C++11. Since C++ is largely compatible with C, this article exploited their similarities for writing the second example. In some aspects, C++ is easier to use because it partially relieves the burden of explicitly managing memory. But the syntax is more complex because it introduces the possibility of writing classes for OOP. However, it is still possible to write software in C with the OOP approach. Since OOP is a style of programming, it can be used in any language. There are some great examples of OOP in C, such as the [GObject][59] and [Jansson][60] libraries.
|
||||
|
||||
For number crunching, I prefer working in C99 due to its simpler syntax and widespread support. Until recently, C++11 was not as widely supported, and I tended to avoid the rough edges in the previous versions. For more complex software, C++ could be a good choice.
|
||||
|
||||
Do you use C or C++ for data science as well? Share your experiences in the comments.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/20/2/c-data-science
|
||||
|
||||
作者:[Cristiano L. Fontana][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[译者ID](https://github.com/译者ID)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://opensource.com/users/cristianofontana
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/metrics_data_dashboard_system_computer_analytics.png?itok=oxAeIEI- (metrics and data shown on a computer screen)
|
||||
[2]: https://opensource.com/article/18/9/top-3-python-libraries-data-science
|
||||
[3]: https://opensource.com/article/19/5/learn-python-r-data-science
|
||||
[4]: https://en.wikipedia.org/wiki/C99
|
||||
[5]: https://en.wikipedia.org/wiki/C%2B%2B11
|
||||
[6]: https://en.wikipedia.org/wiki/Anscombe%27s_quartet
|
||||
[7]: https://opensource.com/article/20/2/python-gnu-octave-data-science
|
||||
[8]: https://en.wikipedia.org/wiki/Command-line_interface
|
||||
[9]: https://en.wikipedia.org/wiki/Graphical_user_interface
|
||||
[10]: https://gitlab.com/cristiano.fontana/polyglot_fit
|
||||
[11]: https://en.wikipedia.org/wiki/Comma-separated_values
|
||||
[12]: https://en.wikipedia.org/wiki/C_%28programming_language%29
|
||||
[13]: https://www.tiobe.com/tiobe-index/
|
||||
[14]: https://redmonk.com/sogrady/2019/07/18/language-rankings-6-19/
|
||||
[15]: http://pypl.github.io/PYPL.html
|
||||
[16]: https://octoverse.github.com/
|
||||
[17]: https://en.wikipedia.org/wiki/Compiled_language
|
||||
[18]: https://en.wikipedia.org/wiki/Compiler
|
||||
[19]: https://en.wikipedia.org/wiki/Machine_code
|
||||
[20]: https://en.wikipedia.org/wiki/C_standard_library
|
||||
[21]: https://en.wiktionary.org/wiki/number-crunching
|
||||
[22]: https://en.wikipedia.org/wiki/Boilerplate_code
|
||||
[23]: https://clang.llvm.org/
|
||||
[24]: https://gcc.gnu.org/
|
||||
[25]: https://www.gnu.org/software/gsl/
|
||||
[26]: http://www.gnuplot.info/
|
||||
[27]: https://en.wikipedia.org/wiki/Berkeley_Software_Distribution
|
||||
[28]: https://getfedora.org/
|
||||
[29]: https://en.wikipedia.org/wiki/Comment_(computer_programming)
|
||||
[30]: https://en.wikipedia.org/wiki/Include_directive
|
||||
[31]: https://en.wikipedia.org/wiki/Linker_%28computing%29
|
||||
[32]: https://en.wikipedia.org/wiki/Entry_point#C_and_C++
|
||||
[33]: https://gitlab.com/cristiano.fontana/polyglot_fit/-/blob/master/fitting_C99.c
|
||||
[34]: https://en.wikipedia.org/wiki/Linked_list#Singly_linked_list
|
||||
[35]: http://man7.org/linux/man-pages/man3/queue.3.html
|
||||
[36]: https://en.wikipedia.org/wiki/Printf_format_string
|
||||
[37]: http://www.opengroup.org/onlinepubs/009695399/functions/ferror.html
|
||||
[38]: http://www.opengroup.org/onlinepubs/009695399/functions/feof.html
|
||||
[39]: http://man7.org/linux/man-pages/man3/getline.3.html
|
||||
[40]: https://en.wikipedia.org/wiki/POSIX
|
||||
[41]: https://en.wikipedia.org/wiki/Lexical_analysis#Token
|
||||
[42]: http://man7.org/linux/man-pages/man3/strtok.3.html
|
||||
[43]: http://www.opengroup.org/onlinepubs/009695399/functions/strtok.html
|
||||
[44]: http://www.opengroup.org/onlinepubs/009695399/functions/sscanf.html
|
||||
[45]: http://www.opengroup.org/onlinepubs/009695399/functions/malloc.html
|
||||
[46]: http://man7.org/linux/man-pages/man3/malloc.3.html
|
||||
[47]: https://www.gnu.org/software/gsl/doc/html/lls.html
|
||||
[48]: https://en.wikipedia.org/wiki/Memory_leak
|
||||
[49]: http://www.opengroup.org/onlinepubs/009695399/functions/free.html
|
||||
[50]: http://www.opengroup.org/onlinepubs/009695399/functions/printf.html
|
||||
[51]: http://www.opengroup.org/onlinepubs/009695399/functions/fprintf.html
|
||||
[52]: https://opensource.com/sites/default/files/uploads/fit_c99.png (Plot and fit of the dataset obtained with C99)
|
||||
[53]: https://en.wikipedia.org/wiki/C%2B%2B
|
||||
[54]: http://www.cplusplus.com/info/history/
|
||||
[55]: https://en.wikipedia.org/wiki/Object-oriented_programming
|
||||
[56]: https://en.wikipedia.org/wiki/Sequence_container_%28C%2B%2B%29#Vector
|
||||
[57]: https://en.wikipedia.org/wiki/C%2B%2B_Standard_Library
|
||||
[58]: https://opensource.com/sites/default/files/uploads/fit_cpp11.png (Plot and fit of the dataset obtained with C++11)
|
||||
[59]: https://en.wikipedia.org/wiki/GObject
|
||||
[60]: http://www.digip.org/jansson/
|
118
sources/tech/20200225 3 eBook readers for the Linux desktop.md
Normal file
118
sources/tech/20200225 3 eBook readers for the Linux desktop.md
Normal file
@ -0,0 +1,118 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: ( )
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (3 eBook readers for the Linux desktop)
|
||||
[#]: via: (https://opensource.com/article/20/2/linux-ebook-readers)
|
||||
[#]: author: (Scott Nesbitt https://opensource.com/users/scottnesbitt)
|
||||
|
||||
3 eBook readers for the Linux desktop
|
||||
======
|
||||
Any of these open source eBook applications will make it easy to read
|
||||
your books on a larger screen.
|
||||
![Computer browser with books on the screen][1]
|
||||
|
||||
I usually read eBooks on my phone or with my Kobo eReader. I've never been comfortable reading books on larger screens. However, many people regularly read books on their laptops or desktops. If you are one of them (or think you might be), I'd like to introduce you to three eBook readers for the Linux desktop.
|
||||
|
||||
### Bookworm
|
||||
|
||||
[Bookworm][2] is billed as a "simple, focused eBook reader." And it is. Bookworm has a basic set of features, which some people will complain about being _too basic_ or lacking _functionality_ (whatever that word means). Bookworm does one thing and does it well without unnecessary frills.
|
||||
|
||||
The application's interface is very clean and uncluttered.
|
||||
|
||||
![Bookworm e-book application][3]
|
||||
|
||||
You navigate through a book by pressing:
|
||||
|
||||
* The space bar to move down a page
|
||||
* The Down and Up arrow keys to move down and up a single line
|
||||
* The Right and Left arrow keys to jump to the next or previous chapter
|
||||
|
||||
|
||||
|
||||
You can also annotate portions of a book and insert bookmarks to jump back to a page.
|
||||
|
||||
![Annotations in Bookworm][4]
|
||||
|
||||
Bookworm doesn't have many configuration options. You can change the size and spacing of a book's font, enable a two-page reading view or dark mode, and add folders that Bookworm will scan to find new eBooks.
|
||||
|
||||
![Bookworm preferences][5]
|
||||
|
||||
Bookworm supports the most widely used eBook formats: EPUB, PDF, MOBI, and [FB2][6]. You can also use Bookworm to read popular digital comic book formats [CBR][7] and CBZ. I've tested Bookworm with only the first three formats. PDF files are readable, but they load slowly and the formatting can be rather ugly.
|
||||
|
||||
### Foliate
|
||||
|
||||
As far as features go, [Foliate][8] is a step or two above Bookworm. Not only does it have several more features, but it also has more configuration options. You get all of that in a zippy, clean, and uncluttered package.
|
||||
|
||||
![Foliate e-book application][9]
|
||||
|
||||
You can navigate through an eBook in Foliate using the space bar, arrow keys, or PgUp and PgDn keys. There's nothing unique there.
|
||||
|
||||
You can also annotate text, look up and translate words and phrases, and look up the meanings of words. If you have a text-to-speech application installed on your computer, Foliate can use it to read books aloud.
|
||||
|
||||
![Annotating a book in Foliate][10]
|
||||
|
||||
Foliate has a few more customization options than Bookworm. You can change a book's font and its size, the spacing of lines, and the size of a book's margins. You can also increase or decrease the brightness and select one of four built-in themes.
|
||||
|
||||
![Foliate settings][11]
|
||||
|
||||
You can read books in the EPUB, MOBI, AZW, and AZW3 formats using Foliate. In case you're wondering, the latter three are closed formats used with books published for Amazon's Kindle eReader
|
||||
|
||||
### Calibre's eBook viewer
|
||||
|
||||
[eBook viewer][12] is a component of the [Calibre][13] eBook management tool. Like its parent, the eBook viewer feature isn't the prettiest piece of software out there.
|
||||
|
||||
![E-book Viewer application][14]
|
||||
|
||||
Don't let that put you off, though. It's a solid desktop eBook reader.
|
||||
|
||||
You navigate through an eBook in Calibre's e-book viewer using the arrow and PgUp/PgDn keys or by pressing the space bar. You can also look up words in an online dictionary and add bookmarks throughout a book. E-book viewer lacks an annotation function, but its built-in search engine is solid, and you can save books as PDFs (though I'm not sure why you'd want to).
|
||||
|
||||
Configuration options are an area where this eBook viewer shines. It has far more of them than both Bookworm and Foliate combined. You can change everything from fonts to the layout of text to how text is broken up into pages. On top of that, you can customize the keyboard shortcuts for using the application and add your favorite dictionary website or sites to help you look up words in a book you're reading.
|
||||
|
||||
![E-book Viewer preferences][15]
|
||||
|
||||
One useful feature of Calibre's eBook viewer is the ability to apply your own CSS file to your e-books. CSS, in case you're wondering, is a way to format web pages (which is what many e-books are made of). If you're a master with CSS, you can copy and paste your CSS file into the **User stylesheet** tab in eBook viewer's Preferences window. That's the ultimate in customization.
|
||||
|
||||
eBook viewer, according to its developer, "can display all the major e-book formats." If you're wondering what those formats are, [here's a list][16]. I've tested it with just a few of those formats and have had no problems with them.
|
||||
|
||||
### Final thought
|
||||
|
||||
Whether you're looking for a simple eBook reader or one with bells and whistles and whatever else, the three applications in this article are good choices. Any of them can make reading an eBook on a larger screen easier.
|
||||
|
||||
* * *
|
||||
|
||||
_This article is based on an article published on [Open Source Musings][17] and appears here via a [CC BY-SA 4.0][18] license._
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/20/2/linux-ebook-readers
|
||||
|
||||
作者:[Scott Nesbitt][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[译者ID](https://github.com/译者ID)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://opensource.com/users/scottnesbitt
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/computer_browser_program_books_read.jpg?itok=iNMWe8Bu (Computer browser with books on the screen)
|
||||
[2]: https://babluboy.github.io/bookworm/
|
||||
[3]: https://opensource.com/sites/default/files/uploads/bookworm-reading.png (Bookworm e-book application)
|
||||
[4]: https://opensource.com/sites/default/files/uploads/bookworm-annotations.png (Annotations in Bookworm)
|
||||
[5]: https://opensource.com/sites/default/files/uploads/bookworm-preferences.png (Bookworm preferences)
|
||||
[6]: https://en.wikipedia.org/wiki/FictionBook
|
||||
[7]: https://en.wikipedia.org/wiki/Comic_book_archive
|
||||
[8]: https://johnfactotum.github.io/foliate/
|
||||
[9]: https://opensource.com/sites/default/files/uploads/foliate-reading.png (Foliate e-book application)
|
||||
[10]: https://opensource.com/sites/default/files/uploads/foliate-annotation_0.png
|
||||
[11]: https://opensource.com/sites/default/files/uploads/foliate-settings.png (Foliate settings)
|
||||
[12]: https://calibre-ebook.com/about
|
||||
[13]: https://opensourcemusings.com/managing-your-ebooks-with-calibre
|
||||
[14]: https://opensource.com/sites/default/files/uploads/e-book_viewer-reading.png (E-book Viewer application)
|
||||
[15]: https://opensource.com/sites/default/files/uploads/ebook-viewer-preferences.png (E-book Viewer preferences)
|
||||
[16]: https://manual.calibre-ebook.com/faq.html#what-formats-does-calibre-support-conversion-to-from
|
||||
[17]: https://opensourcemusings.com/three-ebook-readers-for-the-linux-desktop
|
||||
[18]: https://creativecommons.org/licenses/by-sa/4.0/
|
132
translated/tech/20200217 How to get MongoDB Server on Fedora.md
Normal file
132
translated/tech/20200217 How to get MongoDB Server on Fedora.md
Normal file
@ -0,0 +1,132 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (geekpi)
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (How to get MongoDB Server on Fedora)
|
||||
[#]: via: (https://fedoramagazine.org/how-to-get-mongodb-server-on-fedora/)
|
||||
[#]: author: (Honza Horak https://fedoramagazine.org/author/hhorak/)
|
||||
|
||||
如何在 Fedora 上获取 MongoDB 服务器
|
||||
======
|
||||
|
||||
![][1]
|
||||
|
||||
Mongo(来自 “humongous”)是一个高性能,开源,无模式的面向文档的数据库,它是最受欢迎的 [NoSQL][2] 数据库之一。它使用 JSON 作为文档格式,并且可以在多个服务器节点之间进行扩展和复制。
|
||||
|
||||
### 有关许可证更改的故事
|
||||
|
||||
上游 MongoD 决定更改服务器代码的许可证已经一年多了。先前的许可证是 GNU Affero General Public License v3(AGPLv3)。但是,上游写了一个新许可证,为了使运行 MongoDB 即服务的公司回馈社区。新许可证称为 Server Side Public License(SSPLv1),关于这个及其原理的更多说明,请参见[MongoDB SSPL FAQ][3]。
|
||||
|
||||
Fedora 一直只包含自由软件。当 SSPL 发布后,Fedora [确定][4]它并不是自由软件许可。许可证更改日期(2018 年 10 月)之前发布的所有 MongoDB 版本都可保留在 Fedora 中,但之后再也不更新软件包会带来安全问题。因此,从 Fedora 30 开始,Fedora 社区决定完全[移除 MongoDB 服务器][5]。
|
||||
|
||||
### 开发人员还有哪些选择?
|
||||
|
||||
是的,还有替代方案,例如 PostgreSQL 在最新版本中也支持 JSON,它可以在无法再使用 MongoDB 的情况下使用它。使用 JSONB 类型,索引在 PostgreSQL 中可以很好地工作,其性能可与 MongoDB 媲美,甚至不会受到 ACID 的影响。
|
||||
|
||||
开发人员可能选择 MongoDB 的技术原因并未随许可证而改变,因此许多人仍想使用它。重要的是要意识到,SSPL 许可证仅更改仅针对 MongoDB 服务器。MongoDB 上游还开发了其他项目,例如 MongoDB 工具,C 和 C++ 客户端库以及用于各种动态语言的连接器,这些项目在客户端(要通过网络与服务器通信的应用中)使用。由于这些包的许可证是自由的(主要是 Apache 许可证),因此它们保留在 Fedora 仓库中,因此用户可以将其用于应用开发。
|
||||
|
||||
唯一的变化实际是服务器包本身,它已从 Fedora 仓库中完全删除。让我们看看 Fedora 用户可以如何获取非自由的包。
|
||||
|
||||
### 如何从上游安装 MongoDB 服务器
|
||||
|
||||
当 Fedora 用户想要安装 MongoDB 服务器时,他们需要直接向上游获取 MongoDB。但是,上游不为 Fedora 提供 RPM 包。相反,MongoDB 服务器可以获取源码 tarball,用户需要自己进行编译(这需要一些开发知识),或者 Fedora 用户可以使用一些兼容的包。在兼容的选项中,最好的选择是 RHEL-8 RPM。以下步骤描述了如何安装它们以及如何启动守护进程。
|
||||
|
||||
#### 1\. 使用上游 RPM 创建仓库(RHEL-8 构建)
|
||||
```
|
||||
|
||||
```
|
||||
|
||||
$ sudo cat > /etc/yum.repos.d/mongodb.repo &lt;&lt;EOF
|
||||
[mongodb-upstream]
|
||||
name=MongoDB Upstream Repository
|
||||
baseurl=<https://repo.mongodb.org/yum/redhat/8Server/mongodb-org/4.2/x86\_64/>
|
||||
gpgcheck=1
|
||||
enabled=1
|
||||
gpgkey=<https://www.mongodb.org/static/pgp/server-4.2.asc>
|
||||
EOF
|
||||
```
|
||||
|
||||
```
|
||||
|
||||
#### 2\. 安装元软件包,来拉取服务器和工具包
|
||||
```
|
||||
|
||||
```
|
||||
|
||||
$ sudo dnf install mongodb-org
|
||||
&lt;snipped>
|
||||
Installed:
|
||||
mongodb-org-4.2.3-1.el8.x86_64 mongodb-org-mongos-4.2.3-1.el8.x86_64
|
||||
mongodb-org-server-4.2.3-1.el8.x86_64 mongodb-org-shell-4.2.3-1.el8.x86_64
|
||||
mongodb-org-tools-4.2.3-1.el8.x86_64
|
||||
|
||||
Complete!
|
||||
```
|
||||
|
||||
```
|
||||
|
||||
#### 3\. 启动 MongoDB 守护进程
|
||||
```
|
||||
|
||||
```
|
||||
|
||||
$ sudo systemctl status mongod
|
||||
● mongod.service - MongoDB Database Server
|
||||
Loaded: loaded (/usr/lib/systemd/system/mongod.service; enabled; vendor preset: disabled)
|
||||
Active: active (running) since Sat 2020-02-08 12:33:45 EST; 2s ago
|
||||
Docs: <https://docs.mongodb.org/manual>
|
||||
Process: 15768 ExecStartPre=/usr/bin/mkdir -p /var/run/mongodb (code=exited, status=0/SUCCESS)
|
||||
Process: 15769 ExecStartPre=/usr/bin/chown mongod:mongod /var/run/mongodb (code=exited, status=0/SUCCESS)
|
||||
Process: 15770 ExecStartPre=/usr/bin/chmod 0755 /var/run/mongodb (code=exited, status=0/SUCCESS)
|
||||
Process: 15771 ExecStart=/usr/bin/mongod $OPTIONS (code=exited, status=0/SUCCESS)
|
||||
Main PID: 15773 (mongod)
|
||||
Memory: 70.4M
|
||||
CPU: 611ms
|
||||
CGroup: /system.slice/mongod.service
|
||||
└─15773 /usr/bin/mongod -f /etc/mongod.conf
|
||||
```
|
||||
|
||||
```
|
||||
|
||||
#### 4\. 通过 mongo shell 连接服务器来验证是否运行
|
||||
```
|
||||
|
||||
```
|
||||
|
||||
$ mongo
|
||||
MongoDB shell version v4.2.3
|
||||
connecting to: mongodb://127.0.0.1:27017/?compressors=disabled&amp;gssapiServiceName=mongodb
|
||||
Implicit session: session { "id" : UUID("20b6e61f-c7cc-4e9b-a25e-5e306d60482f") }
|
||||
MongoDB server version: 4.2.3
|
||||
Welcome to the MongoDB shell.
|
||||
For interactive help, type "help".
|
||||
For more comprehensive documentation, see
|
||||
<http://docs.mongodb.org/>
|
||||
\---
|
||||
|
||||
> _
|
||||
```
|
||||
|
||||
```
|
||||
|
||||
就是这样了。如你所见,RHEL-8 包完美兼容,只要 Fedora 包还与 RHEL-8 兼容,它就应该会一直兼容。 请注意,在使用时必须遵守 SSPLv1 许可证。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://fedoramagazine.org/how-to-get-mongodb-server-on-fedora/
|
||||
|
||||
作者:[Honza Horak][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[geekpi](https://github.com/geekpi)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://fedoramagazine.org/author/hhorak/
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://fedoramagazine.org/wp-content/uploads/2020/02/mongodb-816x348.png
|
||||
[2]: https://en.wikipedia.org/wiki/NoSQL
|
||||
[3]: https://www.mongodb.com/licensing/server-side-public-license/faq
|
||||
[4]: https://lists.fedoraproject.org/archives/list/legal@lists.fedoraproject.org/thread/IQIOBOGWJ247JGKX2WD6N27TZNZZNM6C/
|
||||
[5]: https://fedoraproject.org/wiki/Changes/MongoDB_Removal
|
516
translated/tech/20200224 Using C and C-- for data science.md
Normal file
516
translated/tech/20200224 Using C and C-- for data science.md
Normal file
@ -0,0 +1,516 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (wxy)
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (Using C and C++ for data science)
|
||||
[#]: via: (https://opensource.com/article/20/2/c-data-science)
|
||||
[#]: author: (Cristiano L. Fontana https://opensource.com/users/cristianofontana)
|
||||
|
||||
在数据科学中使用 C 和 C++
|
||||
======
|
||||
|
||||
> 让我们使用 C99 和 C++ 11 完成常见的数据科学任务。
|
||||
|
||||
![metrics and data shown on a computer screen][1]
|
||||
|
||||
虽然 [Python][2] 和 [R][3] 之类的语言在数据科学中越来越受欢迎,但是 C 和 C++ 对于高效的数据科学来说是一个不错的选择。在本文中,我们将使用 [C99][4] 和 [C++11][5] 编写一个程序,该程序使用 [Anscombe 的四重奏][6]数据集,下面将对其进行解释。
|
||||
|
||||
我在一篇涉及 [Python 和 GNU Octave][7] 的文章中写了我不断学习语言的动机,值得大家回顾。所有程序都应在[命令行][8]上运行,而不是在[图形用户界面(GUI)][9]上运行。完整的示例可在 [polyglot_fit 存储库][10]中找到。
|
||||
|
||||
### 编程任务
|
||||
|
||||
你将在本系列中编写的程序:
|
||||
|
||||
* 从 [CSV 文件] [11]中读取数据
|
||||
* 用直线插值数据(即 `f(x)=m ⋅ x + q`)
|
||||
* 将结果绘制到图像文件
|
||||
|
||||
这是许多数据科学家遇到的普遍情况。示例数据是 [Anscombe 的四重奏] [6]的第一组,如下表所示。这是一组人工构建的数据,当拟合直线时可以提供相同的结果,但是它们的曲线非常不同。数据文件是一个文本文件,其中的制表符用作列分隔符,几行作为标题。该任务将仅使用第一组(即前两列)。
|
||||
|
||||
[Anscombe 的四重奏][6]
|
||||
|
||||
|
||||
### C 语言的方式
|
||||
|
||||
[C][12] 语言是通用编程语言,是当今使用最广泛的语言之一(依据 [TIOBE 榜单][13]、[RedMonk 编程语言排名][14]、[编程语言流行度榜单][15]和 [GitHub Octoverse 状态][16])。这是一种相当古老的语言(大约诞生在 1973 年),并且用它编写了许多成功的程序(例如 Linux 内核和 Git 仅是其中两个例子)。它也是最接近计算机内部运行的语言之一,因为它直接用于操作内存。它是一种[编译语言] [17];因此,源代码必须由[编译器][18]转换为[机器代码][19]。它的[标准库][20]很小,功能也不多,因此开发了其他库来提供缺少的功能。
|
||||
|
||||
我最常在[数字运算][21]中使用该语言,主要是因为其性能。我觉得使用起来很繁琐,因为它需要很多[样板代码][22],但是它在各种环境中都得到了很好的支持。C99 标准是最新版本,增加了一些漂亮的功能,并且得到了编译器的良好支持。
|
||||
|
||||
我将一路介绍 C 和 C++ 编程的必要背景,以便初学者和高级用户都可以继续学习。
|
||||
|
||||
#### 安装
|
||||
|
||||
要使用 C99 进行开发,你需要一个编译器。我通常使用 [Clang][23],不过 [GCC][24] 是另一个有效的开源编译器。对于线性拟合,我选择使用 [GNU 科学库] [25]。对于绘图,我找不到任何明智的库,因此该程序依赖于外部程序:[Gnuplot] [26]。该示例还使用动态数据结构来存储数据,该结构在[伯克利软件分发版(BSD)][27]中定义。
|
||||
|
||||
在 [Fedora][28] 中安装很容易:
|
||||
|
||||
```
|
||||
sudo dnf install clang gnuplot gsl gsl-devel
|
||||
```
|
||||
|
||||
#### 注释代码
|
||||
|
||||
在 C99 中,[注释][29]的格式是在行的开头放置 `//`,行的其它部分将被解释器丢弃。另外,`/*` 和 `*/` 之间的任何内容也将被丢弃。
|
||||
|
||||
```
|
||||
// 这是一个注释,会被解释器忽略
|
||||
/* 这也被忽略 */
|
||||
```
|
||||
|
||||
#### 必要的库
|
||||
|
||||
库由两部分组成:
|
||||
|
||||
* [头文件][30],其中包含函数说明
|
||||
* 包含函数定义的源文件
|
||||
|
||||
头文件包含在源文件中,而库文件的源文件则与可执行文件[链接][31]。因此,此示例所需的头文件是:
|
||||
|
||||
```
|
||||
// 输入/输出功能
|
||||
#include <stdio.h>
|
||||
// 标准库
|
||||
#include <stdlib.h>
|
||||
// 字符串操作功能
|
||||
#include <string.h>
|
||||
// BSD 队列
|
||||
#include <sys/queue.h>
|
||||
// GSL 科学功能
|
||||
#include <gsl/gsl_fit.h>
|
||||
#include <gsl/gsl_statistics_double.h>
|
||||
```
|
||||
|
||||
#### 主函数
|
||||
|
||||
在 C 语言中,程序必须位于称为主函数 [main()][32]:的特殊函数内:
|
||||
|
||||
```
|
||||
int main(void) {
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
这与上一教程中介绍的 Python 不同,后者将运行在源文件中找到的所有代码。
|
||||
|
||||
#### 定义变量
|
||||
|
||||
在 C 语言中,变量必须在使用前声明,并且必须与类型关联。每当你要使用变量时,都必须决定要在其中存储哪种数据。你也可以指定是否打算将变量用作常量值,这不是必需的,但是编译器可以从此信息中受益。 来自存储库中的 [fitting_C99.c 程序] [33]:
|
||||
|
||||
```
|
||||
const char *input_file_name = "anscombe.csv";
|
||||
const char *delimiter = "\t";
|
||||
const unsigned int skip_header = 3;
|
||||
const unsigned int column_x = 0;
|
||||
const unsigned int column_y = 1;
|
||||
const char *output_file_name = "fit_C99.csv";
|
||||
const unsigned int N = 100;
|
||||
```
|
||||
|
||||
C 语言中的数组不是动态的,从某种意义上说,数组的长度必须事先确定(即,在编译之前):
|
||||
|
||||
```
|
||||
int data_array[1024];
|
||||
```
|
||||
|
||||
由于你通常不知道文件中有多少个数据点,因此请使用[单链接列表][34]。这是一个动态数据结构,可以无限增长。幸运的是,BSD [提供了链表][35]。这是一个示例定义:
|
||||
|
||||
```
|
||||
struct data_point {
|
||||
double x;
|
||||
double y;
|
||||
|
||||
SLIST_ENTRY(data_point) entries;
|
||||
};
|
||||
|
||||
SLIST_HEAD(data_list, data_point) head = SLIST_HEAD_INITIALIZER(head);
|
||||
SLIST_INIT(&head);
|
||||
```
|
||||
|
||||
该示例定义了一个由结构化值组成的 `data_point` 列表,该结构化值同时包含 `x` 值和 `y` 值。语法相当复杂,但是很直观,详细描述它就会太冗长了。
|
||||
|
||||
#### 打印输出
|
||||
|
||||
要在终端上打印,可以使用 [printf()][36] 函数,其功能类似于 Octave 的 `printf()` 函数(在第一篇文章中介绍):
|
||||
|
||||
```
|
||||
printf("#### Anscombe's first set with C99 ####\n");
|
||||
```
|
||||
|
||||
`printf()` 函数不会在打印字符串的末尾自动添加换行符,因此你必须添加换行符。第一个参数是一个字符串,可以包含传递给函数的其他参数的格式信息,例如:
|
||||
|
||||
```
|
||||
printf("Slope: %f\n", slope);
|
||||
```
|
||||
|
||||
#### 读取数据
|
||||
|
||||
现在来到了困难的部分……有一些用 C 语言解析 CSV 文件的库,但是似乎没有一个库足够稳定或流行到可以放入到 Fedora 软件包存储库中。我没有为本教程添加依赖项,而是决定自己编写此部分。同样,讨论这些细节太啰嗦了,所以我只会解释大致的思路。为了简洁起见,将忽略源代码中的某些行,但是你可以在存储库中找到完整的示例。
|
||||
|
||||
首先,打开输入文件:
|
||||
|
||||
```
|
||||
FILE* input_file = fopen(input_file_name, "r");
|
||||
```
|
||||
|
||||
然后逐行读取文件,直到出现错误或文件结束:
|
||||
|
||||
```
|
||||
while (!ferror(input_file) && !feof(input_file)) {
|
||||
size_t buffer_size = 0;
|
||||
char *buffer = NULL;
|
||||
|
||||
getline(&buffer, &buffer_size, input_file);
|
||||
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
[getline()][39] 函数是 [POSIX.1-2008 标准][40]新增的一个不错的函数。它可以读取文件中的整行,并负责分配必要的内存。然后使用 [strtok()][42] 函数将每一行分成<ruby>[字元][41]<rt>token</rt></ruby>。遍历字元,选择所需的列:
|
||||
|
||||
```
|
||||
char *token = strtok(buffer, delimiter);
|
||||
|
||||
while (token != NULL)
|
||||
{
|
||||
double value;
|
||||
sscanf(token, "%lf", &value);
|
||||
|
||||
if (column == column_x) {
|
||||
x = value;
|
||||
} else if (column == column_y) {
|
||||
y = value;
|
||||
}
|
||||
|
||||
column += 1;
|
||||
token = strtok(NULL, delimiter);
|
||||
}
|
||||
```
|
||||
|
||||
最后,当选择了 `x` 和 `y` 值时,将新数据点插入链表中:
|
||||
|
||||
```
|
||||
struct data_point *datum = malloc(sizeof(struct data_point));
|
||||
datum->x = x;
|
||||
datum->y = y;
|
||||
|
||||
SLIST_INSERT_HEAD(&head, datum, entries);
|
||||
```
|
||||
|
||||
[malloc()][46] 函数为新数据点动态分配(保留)一些持久性内存。
|
||||
|
||||
#### 拟合数据
|
||||
|
||||
GSL 线性拟合函数 [gsl_fit_linear()][47] 期望其输入为简单数组。因此,由于你将不知道要创建的数组的大小,因此必须手动分配它们的内存:
|
||||
|
||||
```
|
||||
const size_t entries_number = row - skip_header - 1;
|
||||
|
||||
double *x = malloc(sizeof(double) * entries_number);
|
||||
double *y = malloc(sizeof(double) * entries_number);
|
||||
```
|
||||
|
||||
然后,遍历链接列表以将相关数据保存到数组:
|
||||
|
||||
```
|
||||
SLIST_FOREACH(datum, &head, entries) {
|
||||
const double current_x = datum->x;
|
||||
const double current_y = datum->y;
|
||||
|
||||
x[i] = current_x;
|
||||
y[i] = current_y;
|
||||
|
||||
i += 1;
|
||||
}
|
||||
```
|
||||
|
||||
现在你已经完成了链接列表,请清理它。要**总是**释放已手动分配的内存,以防止[内存泄漏][48]。内存泄漏是糟糕的、糟糕的、糟糕的(重要的话说三遍)。每次内存没有释放时,花园侏儒都会找不到自己的头:
|
||||
|
||||
```
|
||||
while (!SLIST_EMPTY(&head)) {
|
||||
struct data_point *datum = SLIST_FIRST(&head);
|
||||
|
||||
SLIST_REMOVE_HEAD(&head, entries);
|
||||
|
||||
free(datum);
|
||||
}
|
||||
```
|
||||
|
||||
终于,终于!你可以拟合你的数据了:
|
||||
|
||||
```
|
||||
gsl_fit_linear(x, 1, y, 1, entries_number,
|
||||
&intercept, &slope,
|
||||
&cov00, &cov01, &cov11, &chi_squared);
|
||||
const double r_value = gsl_stats_correlation(x, 1, y, 1, entries_number);
|
||||
|
||||
printf("Slope: %f\n", slope);
|
||||
printf("Intercept: %f\n", intercept);
|
||||
printf("Correlation coefficient: %f\n", r_value);
|
||||
```
|
||||
|
||||
#### 绘图
|
||||
|
||||
你必须使用外部程序进行绘图。因此,将拟合数据保存到外部文件:
|
||||
|
||||
```
|
||||
const double step_x = ((max_x + 1) - (min_x - 1)) / N;
|
||||
|
||||
for (unsigned int i = 0; i < N; i += 1) {
|
||||
const double current_x = (min_x - 1) + step_x * i;
|
||||
const double current_y = intercept + slope * current_x;
|
||||
|
||||
fprintf(output_file, "%f\t%f\n", current_x, current_y);
|
||||
}
|
||||
```
|
||||
|
||||
用于绘制两个文件的 Gnuplot 命令是:
|
||||
|
||||
```
|
||||
plot 'fit_C99.csv' using 1:2 with lines title 'Fit', 'anscombe.csv' using 1:2 with points pointtype 7 title 'Data'
|
||||
```
|
||||
|
||||
#### 结果
|
||||
|
||||
在运行程序之前,你必须编译它:
|
||||
|
||||
```
|
||||
clang -std=c99 -I/usr/include/ fitting_C99.c -L/usr/lib/ -L/usr/lib64/ -lgsl -lgslcblas -o fitting_C99
|
||||
```
|
||||
|
||||
这个命令告诉编译器使用 C99 标准,读取 `fitting_C99.c` 文件,加载 `gsl` 和 `gslcblas` 库,并将结果保存到 `fitting_C99`。命令行上的结果输出为:
|
||||
|
||||
```
|
||||
#### Anscombe's first set with C99 ####
|
||||
Slope: 0.500091
|
||||
Intercept: 3.000091
|
||||
Correlation coefficient: 0.816421
|
||||
```
|
||||
|
||||
这是用 Gnuplot 生成的结果图像。
|
||||
|
||||
![Plot and fit of the dataset obtained with C99][52]
|
||||
|
||||
### C++11 方式
|
||||
|
||||
[C++][53] 语言是一种通用编程语言,也是当今使用的最受欢迎的语言之一。它是作为 [C 的继承人][54]创建的(诞生于 1983 年),重点是[面向对象程序设计(OOP)][55]。C++ 通常被视为 C 的超集,因此 C 程序应该能够使用 C++ 编译器进行编译。这并非完全正确,因为在某些极端情况下它们的行为有所不同。 根据我的经验,C++ 比 C 需要更少的样板代码,但是如果要进行对象开发,语法会更困难。C++11 标准是最新版本,增加了一些漂亮的功能,并且或多或少得到了编译器的支持。
|
||||
|
||||
由于 C++ 在很大程度上与 C 兼容,因此我将仅强调两者之间的区别。我在本部分中没有涵盖的任何部分,则意味着它与 C 中的相同。
|
||||
|
||||
#### 安装
|
||||
|
||||
这个 C++ 示例的依赖项与 C 示例相同。 在 Fedora 上,运行:
|
||||
|
||||
```
|
||||
sudo dnf install clang gnuplot gsl gsl-devel
|
||||
```
|
||||
|
||||
#### 必要的库
|
||||
|
||||
库的工作方式与 C 语言相同,但是 `include` 指令略有不同:
|
||||
|
||||
|
||||
```
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
|
||||
extern "C" {
|
||||
#include <gsl/gsl_fit.h>
|
||||
#include <gsl/gsl_statistics_double.h>
|
||||
}
|
||||
```
|
||||
|
||||
由于 GSL 库是用 C 编写的,因此你必须将这种特殊性告知编译器。
|
||||
|
||||
#### 定义变量
|
||||
|
||||
与 C 语言相比,C++ 支持更多的数据类型(类),例如,与其 C 语言版本相比,`string` 类型具有更多的功能。相应地更新变量的定义:
|
||||
|
||||
```
|
||||
const std::string input_file_name("anscombe.csv");
|
||||
```
|
||||
|
||||
对于字符串之类的结构化对象,你可以定义变量而无需使用 `=` 符号。
|
||||
|
||||
#### 打印输出
|
||||
|
||||
你可以使用 `printf()` 函数,但是 `cout` 对象更惯用。使用运算符 `<<` 来指示要使用 `cout` 打印的字符串(或对象):
|
||||
|
||||
```
|
||||
std::cout << "#### Anscombe's first set with C++11 ####" << std::endl;
|
||||
|
||||
...
|
||||
|
||||
std::cout << "Slope: " << slope << std::endl;
|
||||
std::cout << "Intercept: " << intercept << std::endl;
|
||||
std::cout << "Correlation coefficient: " << r_value << std::endl;
|
||||
```
|
||||
|
||||
#### 读取数据
|
||||
|
||||
该方案与以前相同。将打开文件并逐行读取文件,但语法不同:
|
||||
|
||||
```
|
||||
std::ifstream input_file(input_file_name);
|
||||
|
||||
while (input_file.good()) {
|
||||
std::string line;
|
||||
|
||||
getline(input_file, line);
|
||||
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
使用与 C99 示例相同的功能提取行字元。代替使用标准的 C 数组,而是使用两个[向量][56]。向量是 [C++ 标准库][57]中对 C 数组的扩展,它允许动态管理内存而无需显式调用 `malloc()`:
|
||||
|
||||
```
|
||||
std::vector<double> x;
|
||||
std::vector<double> y;
|
||||
|
||||
// Adding an element to x and y:
|
||||
x.emplace_back(value);
|
||||
y.emplace_back(value);
|
||||
```
|
||||
|
||||
#### 拟合数据
|
||||
|
||||
要在 C++ 中拟合,你不必遍历列表,因为向量可以保证具有连续的内存。你可以将向量缓冲区的指针直接传递给拟合函数:
|
||||
|
||||
```
|
||||
gsl_fit_linear(x.data(), 1, y.data(), 1, entries_number,
|
||||
&intercept, &slope,
|
||||
&cov00, &cov01, &cov11, &chi_squared);
|
||||
const double r_value = gsl_stats_correlation(x.data(), 1, y.data(), 1, entries_number);
|
||||
|
||||
std::cout << "Slope: " << slope << std::endl;
|
||||
std::cout << "Intercept: " << intercept << std::endl;
|
||||
std::cout << "Correlation coefficient: " << r_value << std::endl;
|
||||
```
|
||||
|
||||
#### 绘图
|
||||
|
||||
使用与以前相同的方法进行绘图。 写入文件:
|
||||
|
||||
```
|
||||
const double step_x = ((max_x + 1) - (min_x - 1)) / N;
|
||||
|
||||
for (unsigned int i = 0; i < N; i += 1) {
|
||||
const double current_x = (min_x - 1) + step_x * i;
|
||||
const double current_y = intercept + slope * current_x;
|
||||
|
||||
output_file << current_x << "\t" << current_y << std::endl;
|
||||
}
|
||||
|
||||
output_file.close();
|
||||
```
|
||||
|
||||
然后使用 Gnuplot 进行绘图。
|
||||
|
||||
#### 结果
|
||||
|
||||
在运行程序之前,必须使用类似的命令对其进行编译:
|
||||
|
||||
```
|
||||
clang++ -std=c++11 -I/usr/include/ fitting_Cpp11.cpp -L/usr/lib/ -L/usr/lib64/ -lgsl -lgslcblas -o fitting_Cpp11
|
||||
```
|
||||
|
||||
命令行上的结果输出为:
|
||||
|
||||
```
|
||||
#### Anscombe's first set with C++11 ####
|
||||
Slope: 0.500091
|
||||
Intercept: 3.00009
|
||||
Correlation coefficient: 0.816421
|
||||
```
|
||||
|
||||
这就是用 Gnuplot 生成的结果图像。
|
||||
|
||||
![Plot and fit of the dataset obtained with C++11][58]
|
||||
|
||||
### 结论
|
||||
|
||||
本文提供了用 C99 和 C++11 编写的数据拟合和绘图任务的示例。由于 C++ 在很大程度上与 C 兼容,因此本文利用了它们的相似性来编写了第二个示例。在某些方面,C++ 更易于使用,因为它部分减轻了显式管理内存的负担。但是其语法更加复杂,因为它引入了为 OOP 编写类的可能性。但是,仍然可以用 C 使用 OOP 方法编写软件。由于 OOP 是一种编程风格,因此可以以任何语言使用。在 C 中有一些很好的 OOP 示例,例如 [GObject][59] 和 [Jansson][60]库。
|
||||
|
||||
对于数字运算,我更喜欢在 C99 中进行,因为它的语法更简单并且得到了广泛的支持。直到最近,C++11 还没有得到广泛的支持,我倾向于避免使用先前版本中的粗糙不足之处。对于更复杂的软件,C++ 可能是一个不错的选择。
|
||||
|
||||
你是否也将 C 或 C++ 用于数据科学? 在评论中分享你的经验。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/20/2/c-data-science
|
||||
|
||||
作者:[Cristiano L. Fontana][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[wxy](https://github.com/wxy)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://opensource.com/users/cristianofontana
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/metrics_data_dashboard_system_computer_analytics.png?itok=oxAeIEI- (metrics and data shown on a computer screen)
|
||||
[2]: https://opensource.com/article/18/9/top-3-python-libraries-data-science
|
||||
[3]: https://opensource.com/article/19/5/learn-python-r-data-science
|
||||
[4]: https://en.wikipedia.org/wiki/C99
|
||||
[5]: https://en.wikipedia.org/wiki/C%2B%2B11
|
||||
[6]: https://en.wikipedia.org/wiki/Anscombe%27s_quartet
|
||||
[7]: https://opensource.com/article/20/2/python-gnu-octave-data-science
|
||||
[8]: https://en.wikipedia.org/wiki/Command-line_interface
|
||||
[9]: https://en.wikipedia.org/wiki/Graphical_user_interface
|
||||
[10]: https://gitlab.com/cristiano.fontana/polyglot_fit
|
||||
[11]: https://en.wikipedia.org/wiki/Comma-separated_values
|
||||
[12]: https://en.wikipedia.org/wiki/C_%28programming_language%29
|
||||
[13]: https://www.tiobe.com/tiobe-index/
|
||||
[14]: https://redmonk.com/sogrady/2019/07/18/language-rankings-6-19/
|
||||
[15]: http://pypl.github.io/PYPL.html
|
||||
[16]: https://octoverse.github.com/
|
||||
[17]: https://en.wikipedia.org/wiki/Compiled_language
|
||||
[18]: https://en.wikipedia.org/wiki/Compiler
|
||||
[19]: https://en.wikipedia.org/wiki/Machine_code
|
||||
[20]: https://en.wikipedia.org/wiki/C_standard_library
|
||||
[21]: https://en.wiktionary.org/wiki/number-crunching
|
||||
[22]: https://en.wikipedia.org/wiki/Boilerplate_code
|
||||
[23]: https://clang.llvm.org/
|
||||
[24]: https://gcc.gnu.org/
|
||||
[25]: https://www.gnu.org/software/gsl/
|
||||
[26]: http://www.gnuplot.info/
|
||||
[27]: https://en.wikipedia.org/wiki/Berkeley_Software_Distribution
|
||||
[28]: https://getfedora.org/
|
||||
[29]: https://en.wikipedia.org/wiki/Comment_(computer_programming)
|
||||
[30]: https://en.wikipedia.org/wiki/Include_directive
|
||||
[31]: https://en.wikipedia.org/wiki/Linker_%28computing%29
|
||||
[32]: https://en.wikipedia.org/wiki/Entry_point#C_and_C++
|
||||
[33]: https://gitlab.com/cristiano.fontana/polyglot_fit/-/blob/master/fitting_C99.c
|
||||
[34]: https://en.wikipedia.org/wiki/Linked_list#Singly_linked_list
|
||||
[35]: http://man7.org/linux/man-pages/man3/queue.3.html
|
||||
[36]: https://en.wikipedia.org/wiki/Printf_format_string
|
||||
[37]: http://www.opengroup.org/onlinepubs/009695399/functions/ferror.html
|
||||
[38]: http://www.opengroup.org/onlinepubs/009695399/functions/feof.html
|
||||
[39]: http://man7.org/linux/man-pages/man3/getline.3.html
|
||||
[40]: https://en.wikipedia.org/wiki/POSIX
|
||||
[41]: https://en.wikipedia.org/wiki/Lexical_analysis#Token
|
||||
[42]: http://man7.org/linux/man-pages/man3/strtok.3.html
|
||||
[43]: http://www.opengroup.org/onlinepubs/009695399/functions/strtok.html
|
||||
[44]: http://www.opengroup.org/onlinepubs/009695399/functions/sscanf.html
|
||||
[45]: http://www.opengroup.org/onlinepubs/009695399/functions/malloc.html
|
||||
[46]: http://man7.org/linux/man-pages/man3/malloc.3.html
|
||||
[47]: https://www.gnu.org/software/gsl/doc/html/lls.html
|
||||
[48]: https://en.wikipedia.org/wiki/Memory_leak
|
||||
[49]: http://www.opengroup.org/onlinepubs/009695399/functions/free.html
|
||||
[50]: http://www.opengroup.org/onlinepubs/009695399/functions/printf.html
|
||||
[51]: http://www.opengroup.org/onlinepubs/009695399/functions/fprintf.html
|
||||
[52]: https://opensource.com/sites/default/files/uploads/fit_c99.png (Plot and fit of the dataset obtained with C99)
|
||||
[53]: https://en.wikipedia.org/wiki/C%2B%2B
|
||||
[54]: http://www.cplusplus.com/info/history/
|
||||
[55]: https://en.wikipedia.org/wiki/Object-oriented_programming
|
||||
[56]: https://en.wikipedia.org/wiki/Sequence_container_%28C%2B%2B%29#Vector
|
||||
[57]: https://en.wikipedia.org/wiki/C%2B%2B_Standard_Library
|
||||
[58]: https://opensource.com/sites/default/files/uploads/fit_cpp11.png (Plot and fit of the dataset obtained with C++11)
|
||||
[59]: https://en.wikipedia.org/wiki/GObject
|
||||
[60]: http://www.digip.org/jansson/
|
Loading…
Reference in New Issue
Block a user