LINUX.ORG.RU
ФорумTalks

Занимательная математика; прогрессии и кубические корни

 ,


2

2

Есть тут у меня в закромах такая вещь как:

#include <stdio.h>
#include <math.h>

int
main()
{
    double          s = 0,
                    d,
                    d2 = 0,
                    p = 1.0 / 3.0;
    for (d = 1; d < 3000; d += d2) {
        s += d;
        d2 += 6;
        printf("%lf, %lf\n", s, pow(s, p));
    }
    return 0;
}
Результат выполнения кода:
1.000000, 1.000000
8.000000, 2.000000
27.000000, 3.000000
64.000000, 4.000000
125.000000, 5.000000
216.000000, 6.000000
343.000000, 7.000000
512.000000, 8.000000
729.000000, 9.000000
1000.000000, 10.000000
1331.000000, 11.000000
1728.000000, 12.000000
2197.000000, 13.000000
2744.000000, 14.000000
3375.000000, 15.000000
4096.000000, 16.000000
4913.000000, 17.000000
5832.000000, 18.000000
6859.000000, 19.000000
8000.000000, 20.000000
9261.000000, 21.000000
10648.000000, 22.000000
12167.000000, 23.000000
13824.000000, 24.000000
15625.000000, 25.000000
17576.000000, 26.000000
19683.000000, 27.000000
21952.000000, 28.000000
24389.000000, 29.000000
27000.000000, 30.000000
29791.000000, 31.000000
32768.000000, 32.000000
Возможно, кому-то будет интересна данная закономерность.

★★★★★
Ответ на: комментарий от peregrine

элементарно

В том и дело, что кому как.

saahriktu ★★★★★
() автор топика

В общем-то это довольно тривиально

У вас двойная сумма вида

s(n) = sum f(m) from m = 0 to n, где f(m) = 1 + sum 6*k from k = 0 to m

Сумма прогрессии из полиномов степени p равна полиному степени p + 1. Получаем, что f(m) это полином 1+1 = второй степени, тогда s(m) это полином 2+1 = третьей степени.

У вас четыре свободных параметра, это начальные значения s, d, d2, а также прирост d2 за каждый шаг цикла.

При любых значениях этих четырёх чисел будет получаться полином s(n) = a*n^3 + b*n^2 + c*n + d, вопрос лишь только в коэффициентах. Коэффициентов тоже четыре. Мы всегда можем подобрать те четыре свободных параметра, чтобы получилось a = 1, b = 0, c = 0, d = 0, что вы и сделали.

Crocodoom ★★★★★
()
(n+1)^3 - n^3 = (n+1 - n) ((n+1)^2 +n(n+1) + n^2) = 3n^2 + 3n + 1
(3(n+1)^2 + 3(n+1) + 1) - (3n^2 + 3n + 1) = 6n + 6
(6(n+1) + 6) - (6n + 6) = 6
aquadon ★★★★★
()

Когда я ещё не забыл математику, писал вот такой код. Правда, наверное, в нём есть косяки - но считает он верно.

#include <stdlib.h>		// atoll()
#include <stdio.h>		// printf()
#include <stdint.h>		// uint64_t
#include <string.h>		// memset()

#define max(a,b) ((a>=b)?(a):(b))
#define min(a,b) ((a>=b)?(b):(a))

#define TRUE (1)
#define FALSE (0)

void nod(int32_t h, int32_t m, int32_t * px, int32_t * py)
{
    // a >= b
    // d = NOD(a,b) = 1
    // ax + by = d = 1
    int32_t a, b;
    int sig = 0;
    a = max(h, m);
    b = min(h, m);
    sig = (h < m) ? 1 : 0;

    int32_t d, x, y;
    int32_t x2, x1;
    int32_t y2, y1;
    int32_t q, r;

    if (b == 0) {
	d = a;
	x = 1;
	y = 0;
	*px = x;
	*py = y;
	return;
    }
    x2 = 1;
    x1 = 0;
    y2 = 0;
    y1 = 1;
    while (b > 0) {
	q = a / b;
	r = a - q * b;
	x = x2 - q * x1;
	y = y2 - q * y1;
	a = b;
	b = r;
	x2 = x1;
	x1 = x;
	y2 = y1;
	y1 = y;
    }
    d = a;
    x = x2;
    y = y2;
    if (sig == 0) {
	*px = x;
	*py = y;
    } else {
	*px = y;
	*py = x;
    }
    return;
}

int main(int argc, char **argv)
{
    if (argc < 4) {
	return -1;
    }
    int32_t h, m;
    int32_t x, y;

    h = atoll(argv[1]);
    m = atoll(argv[2]);
    nod(h, m, &x, &y);

    int32_t u, v;
    u = h * x;
    v = m * y;

    int32_t z;
    int32_t k;
    k = atoll(argv[3]);

    printf("h = %ld\n", h);
    printf("m = %ld\n", m);
    printf("k = %ld\n", k);

    printf("(%ld,%ld)\n", k, m * h);

    int32_t *pK1u = malloc((k - 1) * sizeof(int32_t));
    int32_t *pK1v = malloc((k - 1) * sizeof(int32_t));
    int32_t *pK2u = malloc((k - 1) * sizeof(int32_t));
    int32_t *pK2v = malloc((k - 1) * sizeof(int32_t));
    int32_t *pK3u = malloc((m * h) * sizeof(int32_t));
    int32_t *pK3v = malloc((m * h) * sizeof(int32_t));
    printf("----\n");
    for (z = 1; z <= k - 1; z++) {
	int32_t u1 = u * z;
	int32_t v1 = v * z;
	while (v1 > m * h) {
	    v1 = v1 - m * h;
	    u1 = u1 + m * h;
	}
	while (v1 < 1) {
	    v1 = v1 + m * h;
	    u1 = u1 - m * h;
	}
	pK1u[z - 1] = u1;
	pK1v[z - 1] = v1;
	printf("%d %d\n", u1, v1);
    }
    printf("----\n");
    for (z = 1; z <= k - 1; z++) {
	int32_t u2 = u * z;
	int32_t v2 = v * z;
	while (u2 > m * h) {
	    u2 = u2 - m * h;
	    v2 = v2 + m * h;
	}
	while (u2 < 1) {
	    u2 = u2 + m * h;
	    v2 = v2 - m * h;
	}
	pK2u[z - 1] = u2;
	pK2v[z - 1] = v2;
	printf("%d %d\n", u2, v2);
    }
    printf("----\n");
    for (z = k; z <= k + m * h - 1; z++) {
	int32_t u3 = u * z;
	int32_t v3 = v * z;
	while (u3 <= 0) {
	    u3 = u3 + m * h;
	}
	while (v3 <= 0) {
	    v3 = v3 + m * h;
	}
	pK3u[z - k] = u3;
	pK3v[z - k] = v3;
	printf("%d %d\n", u3, v3);
    }
    int32_t *pADD = malloc((k + m * h) * (k + m * h) * sizeof(int32_t));
    memset(pADD, 0x00, (k + m * h) * (k + m * h) * sizeof(int32_t));
    printf("----\n");
    int i, j;
    for (i = k; i <= k + m * h - 1; i++) {
	for (j = k; j <= k + m * h - 1; j++) {
	    int32_t t;
	    t = pK3u[i - k] + pK3v[j - k];
	    while (t > k + m * h - 1) {
		t -= m * h;
	    }
	    while (t < k) {
		t += m * h;
	    }
	    pADD[i * (k + m * h) + j] = t;
	}
    }
    for (i = 0; i <= k - 1; i++) {
	for (j = k; j <= k + m * h - 1; j++) {
	    pADD[i * (k + m * h) + j] =
		pADD[(i + m * h) * (k + m * h) + j];
	}
    }
    for (i = k; i <= k + m * h - 1; i++) {
	for (j = 0; j <= k - 1; j++) {
	    pADD[i * (k + m * h) + j] =
		pADD[(i) * (k + m * h) + (j + m * h)];
	}
    }
    for (i = 0; i <= k - 1; i++) {
	pADD[i * (k + m * h) + i] =
	    pADD[(i + m * h) * (k + m * h) + (i + m * h)];
    }
pacify ★★★★★
()
    // признак "фиксированности" элемента, размер - строго (k-1)+(k-1)
    int *pMASK1 = malloc((k - 1) * sizeof(int));	// {0 - not fix, 1 - fix}
    int *pMASK2 = malloc((k - 1) * sizeof(int));

    // варианты для "нефиксированных" элементов
    int *pVECTOR = malloc(k * 2 * sizeof(int));	// {0,1}

    // индексы "нефиксированных" элементов
    // (указывает на нулевые элементы масок)
    int *pINDEX = malloc((k - 1) * 2 * sizeof(int));	// of mask elem.

    int nmx = 0;

    // Заполнение MASK*,INDEX
    int nv1 = 0;
    int nv2 = 0;
    // horizontal
    for (z = 1; z <= k; z++) {
	int32_t u1, v1;
	u1 = pK1u[z - 1];
	v1 = pK1v[z - 1];
	if ((z % m == 0) || (z % h == 0) || (v1 - u1 < k) || (v1 >= k))
	    pMASK1[z - 1] = 1;
	else {
	    pMASK1[z - 1] = 0;
	    pINDEX[nv1] = z;	// 0 .. (k-1)
	    nv1++;
	}
    }
    // vertical
    for (z = 1; z <= k; z++) {
	int32_t u2, v2;
	u2 = pK2u[z - 1];
	v2 = pK2v[z - 1];
	if ((z % m == 0) || (z % h == 0) || (u2 - v2 < k) || (u2 >= k))
	    pMASK2[z - 1] = 1;
	else {
	    pMASK2[z - 1] = 0;
	    pINDEX[nv1 + nv2] = z;	// 0 .. (k-1)
	    nv2++;
	}
    }

    {
	int i;
	printf("mask1: ");
	for (i = 0; i < k - 1; i++)
	    printf("%d ", pMASK1[i]);
	printf("\n");
	printf("mask2: ");
	for (i = 0; i < k - 1; i++)
	    printf("%d ", pMASK2[i]);
	printf("\n");
    }

    {
	int nv = nv1 + nv2;	// <= (k-1)*2

	int iv;
	for (iv = 0; iv < nv; iv++)
	    pVECTOR[iv] = 0;

	// Для каждого заполненного pVECTOR[]
	void print() {
	    int iv, jv;
	    for (iv = 0; iv < nv; iv++) {
		// MASK1
		if (iv < nv1) {
		    int j = pINDEX[iv];

		    if (pVECTOR[iv] == 1) {
			int i;
			pADD[(0) * (k + m * h) + (j)] =
			    pADD[(0 + m * h) * (k + m * h) + (j + m * h)];
			for (i = 1; i <= k - pINDEX[iv] - 1; i++) {
			    j = pINDEX[iv] + i;
			    int32_t v_new =
				pADD[(i + m * h) * (k + m * h) +
				     (j + m * h)];
			    if (v_new > k + m * h - 1)
				v_new -= m * h;
			    pADD[(i) * (k + m * h) + (j)] = v_new;
			}
		    }
		    if (pVECTOR[iv] == 0) {
			pADD[(0) * (k + m * h) + (j)] = pK1v[j - 1];
			int i;
			int32_t v_start = pADD[(0) * (k + m * h) + (j)];
			for (i = 1; i <= k - pINDEX[iv] - 1; i++) {
			    j = pINDEX[iv] + i;
			    int32_t v_new = (v_start + i);
			    pADD[(i) * (k + m * h) + (j)] =
				(v_new >
				 k + m * h - 1 ? v_new - m * h : v_new);
			}
		    }
		}
		// MASK2
		else {
		    int i = pINDEX[iv];

		    if (pVECTOR[iv] == 1) {
			int j;
			pADD[(i) * (k + m * h) + (0)] =
			    pADD[(i + m * h) * (k + m * h) + (0 + m * h)];
			for (j = 1; j <= k - pINDEX[iv] - 1; j++) {
			    i = pINDEX[iv] + j;
			    int32_t v_new =
				pADD[(i + m * h) * (k + m * h) +
				     (j + m * h)];
			    if (v_new > k + m * h - 1)
				v_new -= m * h;
			    pADD[(i) * (k + m * h) + (j)] = v_new;
			}
		    }
		    if (pVECTOR[iv] == 0) {
			pADD[(i) * (k + m * h) + (0)] = pK2u[i - 1];
			int j;
			int32_t v_start = pADD[(i) * (k + m * h) + (0)];
			for (j = 1; j <= k - pINDEX[iv] - 1; j++) {
			    i = pINDEX[iv] + j;
			    int32_t v_new = (v_start + j);
			    pADD[(i) * (k + m * h) + (j)] =
				(v_new >
				 k + m * h - 1 ? v_new - m * h : v_new);
			}
		    }
		}
	    }
	    // check assoc.
	    int ic, jc, kc;
	    int flag_as = 1;
	    for (ic = 0; ic <= k - 1; ic++) {
		for (jc = 0; jc <= k - 1; jc++) {
		    for (kc = 0; kc <= k - 1; kc++) {
			if (pADD
			    [(pADD[(ic) * (k + m * h) + (jc)]) *
			     (k + m * h) + (kc)] !=
			    pADD[(ic) * (k + m * h) +
				 (pADD[(jc) * (k + m * h) + (kc)])]) {
			    flag_as = 0;
			    break;
			}
		    }
		    if (!flag_as)
			break;
		}
		if (!flag_as)
		    break;
	    }
	    if (flag_as) {
		printf("***\n");
		for (i = 0; i <= k + m * h - 1; i++) {
		    for (j = 0; j <= k + m * h - 1; j++) {
			printf(" %2ld", pADD[i * (k + m * h) + j]);
		    }
		    printf("\n");
		}
		nmx++;
	    } else {
		printf("ic = %d, jc = %d, kc = %d\n", ic, jc, kc);
		int iv;
		for (iv = 0; iv < nv; iv++) {
		    printf(" %d", pVECTOR[iv]);
		}
		printf("\n");
	    }
	}

	// MASK1
	{
	    int i, j, jx;
	    for (j = 1; j <= k - 1; j++) {
		if (pMASK1[j - 1] == 1) {
		    pADD[(0) * (k + m * h) + (j)] =
			pADD[(0 + m * h) * (k + m * h) + (j + m * h)];
		    for (i = 1; i <= k - j - 1; i++) {
			jx = j + i;
			int32_t v_new =
			    pADD[(i + m * h) * (k + m * h) + (jx + m * h)];
			if (v_new > k + m * h - 1)
			    v_new -= m * h;
			pADD[(i) * (k + m * h) + (jx)] = v_new;
		    }
		}
	    }
	}
	// MASK2
	{
	    int i, j, ix;
	    for (i = 1; i <= k - 1; i++) {
		if (pMASK2[i - 1] == 1) {
		    pADD[(i) * (k + m * h) + (0)] =
			pADD[(i + m * h) * (k + m * h) + (0 + m * h)];
		    for (j = 1; j <= k - i - 1; j++) {
			ix = i + j;
			int32_t v_new =
			    pADD[(ix + m * h) * (k + m * h) + (j + m * h)];
			if (v_new > k + m * h - 1)
			    v_new -= m * h;
			pADD[(ix) * (k + m * h) + (j)] = v_new;
		    }
		}
	    }
	}

	int i = 0;
	int k = 2;
	print();
	if (nv > 0) {
	    while (TRUE) {
		if (pVECTOR[i] >= k - 1) {
		    pVECTOR[i] = 0;
		    i++;
		    if (i > nv - 1)
			break;
		} else {
		    pVECTOR[i]++;
		    i = 0;
		    print();
		}
	    }
	}
    }
    printf("***\n");
    printf("N = %d\n", nmx);
    return 0;
}
$ ./a.out 3 2 5
pacify ★★★★★
()

Есть тут у меня в закромах

корявый aligner?

mos ★★☆☆☆
()

сори за офтопик, просто не спится, это на java

public static void pows() {
    for ( int n = 1, p = 0; n >= 0; n = n << 1, p++ ) {
        out.println( "2^" + p + "= " + n);
    }
}

/*
    2^0= 1
    2^1= 2
    2^2= 4
    2^3= 8
    2^4= 16
    2^5= 32
    2^6= 64
    2^7= 128
    2^8= 256
    2^9= 512
    2^10= 1024
    2^11= 2048
    2^12= 4096
    2^13= 8192
    2^14= 16384
    2^15= 32768
    2^16= 65536
    2^17= 131072
    2^18= 262144
    2^19= 524288
    2^20= 1048576
    2^21= 2097152
    2^22= 4194304
    2^23= 8388608
    2^24= 16777216
    2^25= 33554432
    2^26= 67108864
    2^27= 134217728
    2^28= 268435456
    2^29= 536870912
    2^30= 1073741824
*/
public static int sumOfDigits( int n) {

    if ( n == 0 ) {
        return 0;
    }

    int s = n % 9;
    return s == 0 ? 9 : s;
}

/*
    0: 0
    1: 1
    9: 9
    115: 7
*/

barberry ★★
()

Ты там... пятый?.. класс только что закончил?

Deleted
()

сдается мне, ты открыл частный случай Бинома Ньютона для степени 3

anto215 ★★
()

Какой-то бред. А за такое использование типов надо бить какой-то увесистой книгой по голове.

fornlr ★★★★★
()
Ответ на: комментарий от fornlr

Какое «такое использование типов»? main() всегда int, а для математических вычислений норма double. Посмотрите как определены дефолтные математические функции в glibc'е. Все они определены через double:

double pow(double x, double y);
double log(double x);
double sin(double x);
...
А для float и long double свои функции:
       double log(double x);
       float logf(float x);
       long double logl(long double x);

       double pow(double x, double y);
       float powf(float x, float y);
       long double powl(long double x, long double y);

       double sin(double x);
       float sinf(float x);
       long double sinl(long double x);

saahriktu ★★★★★
() автор топика
Последнее исправление: saahriktu (всего исправлений: 1)
Ответ на: комментарий от fornlr

Цикл и типы - это разные вещи.

Никого я из себя не строю. Я просто пишу про то, что юзаю. И до ассемблера толком я ещё не успел добраться, и не отрицаю этого. В основном знаю именно Си, да.

saahriktu ★★★★★
() автор топика

А вот тоже самое на Коболе:

        IDENTIFICATION DIVISION.
        PROGRAM-ID. D3.

        DATA DIVISION.
        WORKING-STORAGE SECTION.
        01 S PIC 99999V999 VALUE ZERO.
        01 D PIC 99999V999 VALUE 1.
        01 D2 PIC 99999V999 VALUE ZERO.
        01 P PIC 99999V999999.
        01 X PIC 99999V999.

        PROCEDURE DIVISION. MAIN.
            DIVIDE 1 BY 3 GIVING P
            PERFORM UNTIL D > 3000
                ADD D TO S
                ADD 6 TO D2
                COMPUTE X ROUNDED = S ** P
                DISPLAY S ', ' X
                ADD D2 TO D
            END-PERFORM.
        STOP RUN.
А это на Lisp'е:
(defvar s 0)
(defvar d 1)
(defvar d2 0)
(defvar p (/ 1 3))
(loop while (< d 3000) do
  (setf s (+ s d))
  (setf d2 (+ d2 6))
  (format t "~5,3F, ~5,3F~%" s (expt s p))
  (setf d (+ d d2)))

saahriktu ★★★★★
() автор топика

На Фокале:

01.10 SET S = 0
01.20 SET D = 1
01.30 SET D2 = 0
01.40 SET P = 1 / 3
02.10 IF (D - 3000) 02.20,02.70,02.70
02.20 SET S = S + D
02.30 TYPE S , ", " , S ^ P , !
02.40 SET D2 = D2 + 6
02.50 SET D = D + D2
02.60 GOTO 02.10
02.70 QUIT
На Бейсике:
10 LET S = 0
20 LET D = 1
30 LET D2 = 0
40 LET P = 1 / 3
50 IF D > 3000 THEN GOTO 110
60 LET S = S + D
70 PRINT S ; ", " ; S ^ P
80 LET D2 = D2 + 6
90 LET D = D + D2
100 GOTO 50
110 QUIT

saahriktu ★★★★★
() автор топика
Ответ на: комментарий от saahriktu

именно Си

В C не канон объявлять функции без указания типа параметра, как в вашем коде.

Вообще, мне кажется, что в таком виде он становится понятней:

int main(void)
{
    int d = 1, s = 0;
    for (size_t i = 0; i < 10; i++) {
        d += 6 * i; 
        s += d;
        printf("%i %f\n", s, pow(s, 1.0 / 3));
    }
}

И то, что вы написали - это никакая не прогрессия, а обыкновенный ряд с интересным свойсвом своих членов, как вы заметили. Вот то же, что вы написали, только на понятном диалекте:

#include <iostream>
#include <array>
#include <iterator>
#include <algorithm>
#include <numeric>
#include <string>

int main()
{
    const int n = 10;

    std::array<int, n> elements {1};
    for (size_t i = 1; i < elements.size(); ++i)
        elements[i] = elements[i-1] + 6 * i; // общий член ряда, выраженный рекурентно

    std::array<int, n> series;
    std::partial_sum(begin(elements), end(elements), begin(series)); // заполнение членами ряда

    transform(begin(series), end(series), std::ostream_iterator<std::string> {std::cout, "\n"},
            [] (auto element) {
        // вывод члена ряда и его кубического корня
        return std::to_string(element) + " - " + std::to_string(std::pow(element, 1.0 / 3));
    });
}

Вывод здесь абсолютно такой же

Rot1
()
Последнее исправление: Rot1 (всего исправлений: 1)
Ответ на: комментарий от Rot1

В C не канон объявлять функции без указания типа параметра, как в вашем коде.

main(), по сути, уже определена заранее. Такое обращение к ней как «int main()» возможно только потому, что не всегда и не везде нужно передавать в программы аргументы командной строки.

saahriktu ★★★★★
() автор топика

Почему эта закономерность должна быть интересной? Я без задней мысли, просто правда не понимаю.

Octagon
()
Ответ на: комментарий от Octagon

Потому, что не все математики. А для тех, кто ими не являются, такие закономерности неочевидны, и их нужно ешё как-то обнаруживать. Например, практическим складыванием и вычитанием чисел.

saahriktu ★★★★★
() автор топика

из всего обсуждения и приведённых примеров ясно что :

* c++ более наркоманский чем кобол

* при наличии правильных грибов классический С их уделывает

MKuznetsov ★★★★★
()

Возможно, кому-то будет интересна данная закономерность.

И у белых людей она будет выглядеть скорее так:

#include <stdio.h>
int main(){
 for (int i = 1; i <= 32; i++)
    printf("%i %i\n", i*i*i, i);

}

madcore ★★★★★
()
Ответ на: комментарий от saahriktu

Возможно, я понял, о чем ты...
Но открой учебник по матану, тебя ждет много удивительных открытий.

madcore ★★★★★
()
Последнее исправление: madcore (всего исправлений: 1)
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.