Zapisanie 3 wartości dla int[3] za pomocą rzutowania na long double

0

Głowię się nad pewnym zadaniem.

Kod:

#include <iostream>
using namespace std;

int main() {
	// Tablica z datą {ROK, MIESIAC, DZIEN}
	int date[3];

	date[0] = 2011; // Rok
	date[1] = 10; // Miesiac
	date[2] = 29; // Dzien

	// Wyświetlamy datę
	cout << date[0] << "/" << date[1] << "/" << date[2] << endl;

	// Wskaźnik bez definiowania typu (?)
	void * ptr = &date;
	long double *tmp = static_cast<long double*>(ptr);
	*tmp = (10000*2011)+(10000*11)+10; // coś źle myśle :)
	

	// Wyświetlamy datę
	cout << date[0] << "/" << date[1] << "/" << date[2] << endl;

	return 0;
}

Wynik:

2011/10/29
0/-1706806016/16407

Oczekiwany wynik:

2011/10/29
2011/11/10

Chodzi o pewien trick. Mamy 3 elementową tablicę typu int. Każdy element przechowuje datę, odpowiednio rok, miesiąc, dzień.
Typ int ma 4 bajty, więc cała tablica zapisana jest na 12 bajtach. Zadanie polega na zapisaniu daty za pomocą jednej definicji przypisania, zamiast trzech. Trzeba tutaj skorzystać z pewnej własności, że typ long double ma wielkość 12 bajtów. Pomyślałem, że można użyć do tego wskaźnik bez definiowania typu lub ewentualnie zrobić static_cast <long double="double">. Problem w tym, że nie wiem jak się za to zabrać i jak zapisać liczbę (rok miesiac dzien) tak by wskoczyła do odpowiednich komórek pamięci w tablicy.

0

Nie lepiej do bufora?

char buffor[12];

memcpy(buffor,&date[0],sizeof(int));
memcpy(buffor + 4,&date[1],sizeof(int));
memcpy(buffor + 8,&date[2],sizeof(int));
 
0

Chodzi o to że ma być 1 instrukcja przypisania a nie 3.

0
#include <iostream>
using namespace std;
 
int main() {
        short int * date;
        int rok=2011, mies=10, dzien=29;
        long long int D = (dzien*65536LLU+mies)*65536+rok;
        date=(short*)&D;
        cout << D<<' '<<sizeof(D)<<'\n';       //  <----------- tu trochę magii
        cout << date[0] << "/" << date[1] << "/" << date[2] << endl;    
        return 0;
} 

tak jak jest, otrzymamy

124554708955 8
2011/10/29 

bez zaznaczonego wiersza-8204/-18596/-13396 Zbyt optymistyczny optymizator? (ideone jako C++)

0
*(long double*)(data) = *(long double*)(innadata);
0

Założenie co do zadania jest takie, że ma to być tablica int[3] i w instrukcji zapisu mamy wykorzystać long double (wiedząc, że sizeof(long double) = 12).

 #include <iostream>
using namespace std;

int main() {
	// Tablica z datą {ROK, MIESIAC, DZIEN}
	int date[3];

	date[0] = 2011; // Rok
	date[1] = 11; // Miesiac
	date[2] = 29; // Dzien

	// Wyświetlamy datę
	cout << date[0] << "/" << date[1] << "/" << date[2] << endl;

	// Nowa data
	int dzien = 20;
	int miesiac = 12;
	int rok = 2012;

	*(long double*)(&date) = ((dzien*4294967295+miesiac)*4294967295+rok); // Tutaj jest coś nie tak

	// Wyświetlamy datę
	cout << date[0] << "/" << date[1] << "/" << date[2] << endl;

	return 0;
}

Wynik

2011/11/29
-536870912/-536870976/49187

@Xitami na pewno jest sposób zrobienia tego bez "magii", trzeba tylko wykonać prawidłowo mnożenie liczb.

0

Nie możesz tak robić. Wykonując to mnożenie pozostaje Ci liczba całkowita, która jest konwertowana do liczby long double, dodatkowo pewnie będzie tam przepełnienie, czyli wynik może być dowolny (o ile dobrze pamiętam jest to niezdefiniowane).

Magia w sposobie Xitami polega na tym, że jak masz dwa wskaźniki niekompatybilnych typów do jednej wartości, to zmiana tej wartości przez jeden wskaźnik nie gwarantuje natychmiastowej zmiany wartości przy dereferencji drugiego wskaźnika. Gdyby takiego zachowania nie było, to kompilator by miał utrudnioną operację, praktycznie każda instrukcja mogłaby zmieniać wartości wskazywane przez wskaźnik. Uniemożliwiało by to optymalizacje przez trzymanie wartości w rejestrach, co jest szczególnie ważne na coraz popularniejszych architekturach RISC-owych (choć x86-64 też ma sporo rejestrów). Wywołanie funkcji wyświetlającej dane najprawdopodobniej wymusza wczytanie wartości z pamięci, więc pomaga w tej sytuacji.

Przy tym problemie musisz zobaczyć jak liczby są przechowywane w long double i ewentualnie zastosować bardziej skomplikowane operacje matematyczne, niż samo mnożenie. Zacznij od wikipedii i zastanów jak wprowadzić odpowiednie wartości w odpowiednie miejsca long double (pamiętaj o endianess). Ogólnie pomysł na takie ustawienie daty jest chory, nieprzenośny oraz niepotrzebnie skomplikowany. Jeżeli byś pisał w taki sposób w kodzie produkcyjnym, to jakiś psychopata w końcu ciebie dopadnie.

0

kkardasz
twoje "prawidłowo" wygląda tak: dzien*4294967295, sprawdź ile to jest
(2^32 = 4294967296, wtedy otrzymasz okrąglutkie zero) [razem dwa błędy]

druga sprawa to chcesz by wskaźnik wskazywał na wynik wyrażenia, czyli któryś rejestr (w sumie możliwe, są i takie procesory) w którym nie wiadomo co będzie za chwilę? [błąd trzeci]

Zjarek: "...najprawdopodobniej wymusza wczytanie wartości..."
możliwe, że dzięki temu w ogóle wykonana przypisanie do "date" czegokolwiek.

0

dokładnie tak jak Ci pokazałem, a nie modyfikujesz kod który Ci napisałem:

#include <iostream>
using namespace std;

int main()
{
  // Tablica z datą {ROK, MIESIAC, DZIEN}
  int date[3];

  date[0] = 2011; // Rok
  date[1] = 11; // Miesiac
  date[2] = 29; // Dzien

  // Wyświetlamy datę
  cout << date[0] << "/" << date[1] << "/" << date[2] << endl;

  // Nowa data
  int dzien = 20;
  int miesiac = 12;
  int rok = 2012;
  int tab[3] = {rok,miesiac,dzien};

  *(long double*)(date) = *(long double*)(tab);

  // Wyświetlamy datę
  cout << date[0] << "/" << date[1] << "/" << date[2] << endl;

  return 0;
}
0

a zwróciłeś uwagę na to o czym mówiliśmy? wynik zależy od kompilatora/opcyi onego.
http://ideone.com/I5XIz

0

ja bym powiedział że pomysł mieszczenia daty jako bajtów liczby zmiennoprzecinkowej to jest WTF od samego początku, i należy pomysł porzucić.
float/double ma konkretną strukturę, i bzdury w nim zapisane mogą sypnąć wyjątkiem koprocesora w nieoczekiwanym momencie.

0

tak mi dopiero poszło na ideone:

#include <iostream>
#include <cstring>
using namespace std;
 
int main()
{
  // Tablica z datą {ROK, MIESIAC, DZIEN}
  volatile int date[3];
 
  date[0] = 2011; // Rok
  date[1] = 11; // Miesiac
  date[2] = 29; // Dzien
 
  // Wyświetlamy datę
  cout << date[0] << "/" << date[1] << "/" << date[2] << endl;
 
  // Nowa data
  int dzien = 20;
  int miesiac = 12;
  int rok = 2012;
  volatile int tab[3] = {rok,miesiac,dzien};
 
  *(volatile long double*)(date) = *(volatile long double*)(tab);
  //memcpy(tab,date,sizeof(long double));
 
  // Wyświetlamy datę
  cout << date[0] << "/" << date[1] << "/" << date[2] << endl;
 
  return 0;
}

http://ideone.com/VJRQv

0

czy mnie się zdaje? że jednak nie poszło?

1 użytkowników online, w tym zalogowanych: 0, gości: 1